user2422960
user2422960

Reputation: 1526

AngularJS - Initialize services before controller

I am trying to initialize my applications services before the controller starts running.

I would have thought that i could achieve this by resolving a promise-returning function first:

va.config(['$routeProvider', function($routeProvider) {
$routeProvider.
    when('/', {templateUrl: '../partials/home.php',   controller: 'VaCtrl',resolve: {
        pp: vac.loadData
    }});
}]);


var  vac = va.controller('VaCtrl',function($scope,$http,$q,packingProvider){
    console.dir(packingProvider.data[2]); 
});


vac.loadData = function($http,$timeout,$q,packingProvider){

   $http.post('../sys/core/fetchPacking.php').then(function(promise){
        packingProvider.data = promise.data;

    });

    var defer = $q.defer();
    $timeout(function(){
        defer.resolve();
    },2000);
    return defer.promise;
};

However, the controller is still loaded before the promise has beenr esolved, resulting in the console yelling

Cannot read property '2' of undefined

at me.

What am i doing wrong?

Edit:

Also, the controller seems to get invoked twice, first time with the undefined pacingProvider.data object, and 2 secons later with everything fine.

Upvotes: 0

Views: 5857

Answers (2)

Apoorv Parijat
Apoorv Parijat

Reputation: 871

Instead of using the promise returned by $timeout, you could directly use the promise returned by $http.

Rewrite your loadData fn this way -

vac.loadData = function($http,$timeout,$q,packingProvider){

    var promise = $http.post('../sys/core/fetchPacking.php').then(function(promise){
        packingProvider.data = promise.data;
    });

    return promise;
};

Read the first line in the General Usage section here - $http promise

Also, resolve is a map of dependencies.

resolve - {Object.=} - An optional map of dependencies which should be injected into the controller. If any of these dependencies are promises, the router will wait for them all to be resolved or one to be rejected before the controller is instantiated.

Hence, Angular will automatically expose the map for injection. So, you can do this -

var vac = va.controller('VaCtrl', function($scope, pp){
  // 'pp' is the name of the value in the resolve map for $routeProvider.
  console.dir(pp[2]);
});

Upvotes: 3

Caio Cunha
Caio Cunha

Reputation: 23394

NOTE: although this will solve your problem, this answer is probably the right solution.

Services are always initialized before controllers. The problem, as you stated, is that your promise hasn't resulted yet. The best option for that is to stick to the promises.

Instead of exposing the data object, expose the promise and use it:

vac.loadData = function($http,$timeout,$q,packingProvider){
  packingProvider.data = $http.post('../sys/core/fetchPacking.php');
  return packingProvider.data;
};

And in your controller, always attached to the promise, after the first resolval, it will get resolved in the next tick:

var  vac = va.controller('VaCtrl',function($scope,$http,$q,packingProvider){
  packingProvider.data.then(function(value) {
    console.dir(value[2]);
  }); 
});

Upvotes: 3

Related Questions