1

I have a Controller that is calling a function from my Service, and I only want to load the data from the web once, and presumably cache it (in rootScope? but that can wait...).

I've tried to wrap the function call in an init(), but it doesn't seem to be helping... I am seeing the function being called every time I load the partial.

Perhaps there is something naive about my routing ?

Here's some code:

app.js

'use strict';

    var tab = angular.module('tab', ['ngRoute', 'tab.controllers', 'tab.services']);

    tab.config(['$routeProvider', function($routeProvider) {
      $routeProvider.

        // a bunch of other logic here

        when('/curate', {
            templateUrl: '_partials/curate.html',
            controller: 'CurateController'
        }).

      otherwise({
        redirectTo: '/splash'
      });
    }]);

controllers.js

// other controllers etc 

.controller('CurateController', function($scope, $routeParams, ParseService) {

  // Here's where I'm trying to call the function once.
  // Obviously, if I don't have this in the init() it also calls every time I route to it
  $scope.init = function () {
    ParseService.getArticles(function(results) {
      console.log("Articles: " + results);
      // do stuff with data here
    });
  };

})

services.js

angular.module('tab.services', []);

angular.module('tab.services')

/* PARSE */

.factory('ParseService', function() {

    // Vars etc

    var ParseService = {
      name: "Parse",


      // The function in question
      getArticles : function getArticles(callback) {
        var query = new Parse.Query(Article);
        query.find({
          success : function(results) {
            callback(results);
          },
          error : function(error) {
            alert("Error" + error.message);
          }
        });
      },

    };


    return ParseService;
});

curate.html

<section>
    <div class="container-fluid" ng-controller="CurateController" ng-init="init()">

        <!-- STUFF -->


    </div>
</section>
3
  • 4
    It will always be called because when your partial is loaded, the controller is loaded again too. Commented Nov 12, 2015 at 6:19
  • 2
    and you don't need to write ng-controller when you have defined it in the router settings. Commented Nov 12, 2015 at 6:19
  • I don't? Cool, never caught that. I learned Angular through OnsenUI, and they hide the router from you, so that's why I have that habit. Thanks. Commented Nov 12, 2015 at 6:37

2 Answers 2

1

You aren't showing your service. Just cache it in the service $http call

$http.get(url, { cache: true}).success(...);

--- UPDATED

You should return the promise from your service, rather than pass a callback into it.

Looking at the Parse documentation I couldn't see a way of caching data automatically for you for the web.

You could implement your own caching mechanism, and I'd recommend that be in the Service, not in a controller.

-- EDIT 2

Just remember that a service is a singleton. So it, by design, will only be constructed once.

Sign up to request clarification or add additional context in comments.

3 Comments

It's not a simple http service - it's using Parse. But I'll edit the question to include it (didn't think it was necessary) and see if I can figure out where the cache parameter might fit...
Why do I need a Promise though? Isn't that just for async operations ?
What I meant was you pass a callback to the getArticles function, which is bad practice. Returning the promise is better so you can handle success or failure in a controller.
1

My way to ensure a function is only called once per app like data calls and other initialization I create a controller called AppCtrl and put it on body tag.

index.html

<body ng-controller="AppCtrl">
    <ng-view></ng-view>
</body>

then here in your controllers js

controllers.js

.controller("AppCtrl", function ($scope, ParseServce) {
    // put your initialization code here
    ParseService.getArticles(function(results) {
        console.log("Articles: " + results);
       // do stuff with data here
    });
});

that would probably fix your issue.

Bonus tip, you can cache your data inside your service by storing your data in a private variable since only 1 instance of the service is declared in your app there you get the same data wherever you inject the service to any controller, directive or another service.

services.js

.factory('ParseService', function() {

// Vars etc
var _data = [];
var ParseService = {
  name: "Parse",


  // The function in question
  getArticles : function getArticles(callback) {
    var query = new Parse.Query(Article);
    query.find({
      success : function(results) {
        callback(results);
        // Cache the data
        _data = results;
      },
      error : function(error) {
        alert("Error" + error.message);
      }
    });
  },
  // Get your cached data
  getCachedData: function () {
      return _data;
  }
};

Hope that helps

3 Comments

No... I'm only seeing the controller run once every time I load the page, not twice... at least according to the console.
If you want to ensure your function runs once in a page load why not make a controller above ng-view? What I do is make a AppCtrl in body tag then initialize app constants and data calls in there since it is just called once. ng-route calls its designated controller every time you change route.
That makes sense... can you provide that as an answer - or edit yours ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.