AngularJS : Initialize service with asynchronous data

angular-promise, angularjs, asynchronous, javascript, service

Solution

Have you had a look at `$routeProvider.when('/path',{ resolve:{...}`? It can make the promise approach a bit cleaner:

Expose a promise in your service:

app.service('MyService', function($http) {
    var myData = null;

    var promise = $http.get('data.json').success(function (data) {
      myData = data;
    });

    return {
      promise:promise,
      setData: function (data) {
          myData = data;
      },
      doStuff: function () {
          return myData;//.getSomeData();
      }
    };
});

Add `resolve` to your route config:

app.config(function($routeProvider){
  $routeProvider
    .when('/',{controller:'MainCtrl',
    template:'<div>From MyService:<pre>{{data | json}}</pre></div>',
    resolve:{
      'MyServiceData':function(MyService){
        // MyServiceData will also be injectable in your controller, if you don't want this you could create a new promise with the $q service
        return MyService.promise;
      }
    }})
  }):

Your controller won't get instantiated before all dependencies are resolved:

app.controller('MainCtrl', function($scope,MyService) {
  console.log('Promise is now resolved: '+MyService.doStuff().data)
  $scope.data = MyService.doStuff();
});

I've made an example at plnkr: http://plnkr.co/edit/GKg21XH0RwCMEQGUdZKH?p=preview

Problem

I have an AngularJS service that I want to initialize with some asynchronous data. Something like this: ``` myModule.service('MyService', function($http) { var myData = null; $http.get('data.json').success(function (data) { myData = data; }); return { setData: function (data) { myData = data; }, doStuff: function () { return myData.getSomeData(); } }; }); ``` Obviously this won't work because if something tries to call `doStuff()` before `myData` gets back I will get a null pointer exception. As far as I can tell from reading some of the other questions asked here and here I have a few options, but none of them seem very clean (perhaps I am missing something): Setup Service with "run" When setting up my app do this: ``` myApp.run(function ($http, MyService) { $http.get('data.json').success(function (data) { MyService.setData(data); }); }); ``` Then my service would look like this: ``` myModule.service('MyService', function() { var myData = null; return { setData: function (data) { myData = data; }, doStuff: function () { return myData.getSomeData(); } }; }); ``` This works some of the time but if the asynchronous data happens to take longer than it takes for everything to get initialized I get a null pointer exception when I call `doStuff()` Use promise objects This would probably work. The only downside it everywhere I call MyService I will have to know that doStuff() returns a promise and all the code will have to us `then` to interact with the promise. I would rather just wait until myData is back before loading the my application. Manual Bootstrap ``` angular.element(document).ready(function() { $.getJSON("data.json", function (data) { // can't initialize the data here because the service doesn't exist yet angular.bootstrap(document); // too late to initialize here because something may have already // tried to call doStuff() and would have got a null pointer exception }); }); ``` Global Javascript Var I could send my JSON directly to a global Javascript variable: HTML: ``` <script type="text/javascript" src="data.js"></script> ``` data.js: ``` var dataForMyService = { // myData here }; ``` Then it would be available when initializing `MyService`: ``` myModule.service('MyService', function() { var myData = dataForMyService; return { doStuff: function () { return myData.getSomeData(); } }; }); ``` This would work too, but then I have a global javascript variable which smells bad. Are these my only options? Are one of these options better than the others? I know this is a pretty long question, but I wanted to show that I have tried to explore all my options. Any guidance would greatly be appreciated.

Original source

Related problems