0

I have a table in a database that i need to access before anything else goes on in my website. The values that i get, i'll be using all throughout different controllers, directives, services etc. I thought the best place to store those values would be in the $rootScope so to that end, i did the following:

obApp.run(function($rootScope, ngProgress, $timeout) {
  $.post('phpProcessingPage', function(data){
   $rootScope.domains = JSON.parse(data); //this "domains" property is what i'm interested in
  })
})

I get the domains back without a hitch so all is good. The problem is, when i inject the $rootScope into a service:

obApp.factory('requestOrigin', ['$rootScope', function($rootScope){
   console.log($rootScope.domains); //this is undefined at this point
   return $rootScope.domains; //returns undefined
}]);

It's to be expected that there would be nothing there as the response would come after the service code executed.

The problem is, i use that factory code in multiple controllers and i don't know how to delay it's execution so that it waits until i get data back from my ajax call.

I've tried doing a broadcast but there's no way (that i know of) to delay the retun of the factory even if at some point i do get the results back. How would i go about this problem that i have?

ANSWER:

Scrap the usage of $rootScope for this. The controller where i use the returned results from the service looks like this:

oApp.controller(['serviceName', function(serviceName){
    serviceName.then(function(response){
      //here i have the data from the ajax call, the service made
      //other things to do
    });
}]);

And the service looks like this:

obApp.factory(['serviceName','$http', function(serviceName, $http){
    return $http.post('phpProcessingPage.php', {cache: true});
}]);
Radu Andrei
  • 1,075
  • 10
  • 19
  • It's not unusual that a controller gets data via an ajax call from a service. Why is your case different ? It will be undefined for a second and then populate with values. – Omri Aharon Aug 02 '15 at 17:30
  • Because during that second, errors pop up, because i'm trying to access properties of something undefined. Hence i need to delay the execution until i am certain i have an object who's properties i can access. – Radu Andrei Aug 02 '15 at 17:36
  • using `$rootScope` is an anti-pattern, and building a service that interacts with `$rootScope` is a major code smell. – Claies Aug 02 '15 at 18:01
  • @Claies Don't suppose you have a link to a best practices document, that also has reasoning behind why something is best practice? Not that i don't appreciate your input, however just saying something does not make it true. – Radu Andrei Aug 02 '15 at 18:05
  • I think the angular documentation itself does a good job with this already; it states multiple times that Scopes are meant to provide separation between the model and the view; using `$rootScope` to try to work around this separation is an immediate flag, imo. – Claies Aug 02 '15 at 18:10

2 Answers2

2

I'd say you need to redesign this little thing using promises.

Use a service to store and return this data, and from your controllers/directive/etc, you can do the following:

DomainService.getDomains().then(function () {
    // Do whatever you need, here you'll have the data
});

Now the service should return the data, or fetch it from the server when it doesn't have it when the app is running for the first time:

// Domain service
var domains;

var getDomains = function () {
    // using angular's $q service
    var deferred = $q.defer();

    if (domains) {
        // returns the data without going to the server
        deferred.resolve(domains);
    }  
    else {
        // fetches the data the first time, also notice angular's $http service
        $http.post('phpProcessingPage', data).then(function(response)
            domains = response;
            deferred.resolve(domains);
        });
    }

    return deferred.promise;
}
Omri Aharon
  • 16,959
  • 5
  • 40
  • 58
  • It does not help me at all. I inject this service into a controller. Unless there's something i'mi missing, a service looks like this `service('name',['toInject', function(toInject){ /*doStuffHere*/ return something; }])` This means, that no matter how i defer and work around things, i can not avoid the "return something" from being called. And when it's called, it's undefined - my controller yells at me, "undefined". – Radu Andrei Aug 02 '15 at 18:58
  • Hold that thought. I think this is ok, however i'm having the issue with the controller yelling at me saying what i'm trying to access is undefined. – Radu Andrei Aug 02 '15 at 19:04
0

Instead of using jquery $ service you should use angular $http which return a promise that you can attach to your scope. The promise by definition is defined right away and your scope will be populated when the promise is resolved. On top of that angular template fully understand promises and will display your model in the view as soon as it is ready.

Franck
  • 1,754
  • 1
  • 13
  • 14