Alex
Alex

Reputation: 479

How to instantiate variable before the controllers are loaded

I have a simple AngularJS application. I am now trying to implement a L10n* mechanism into it. For that I have service which loads a strings file and returns an array of key-values. These values are later put into views and controllers.

To keep stuff straight and simple I assign the return array to $rootScope so that every controller/view has access to the same list. I am doing it from the angular.module(...).run() function

And this is where the problem starts - some controllers can access the $rootScope object, whilst some other cant (and return undefined). I suspect this is because the promise is not resolved in time before the first few controllers are loaded.

The question is - how do I make the controllers wait for the resource to be loaded?

Auxiliary question - Why can GenericListController use $scope.localisation but ListController cant?

service declaration

app.factory("StringsTranslationService", function($http) {

    var getData = function(locale) {

        return $http({method:"GET", url:'public/resources/strings_'+locale+'.txt'}).then(function(result){
            return result.data[0];
        });
    };
    return { getData: getData };
});

load data from service to $rootScope in app.js

app.run(function($rootScope,StringsTranslationService) {
    var myDataPromise = StringsTranslationService.getData('en');
    myDataPromise.then(function(result) {
        $rootScope.localisation=result;
    });
});

Finally try to use in controller.js:

var app=angular.module('myApp');

app.controller('ListController', function ($scope, $controller){
    console.log($scope.localisation["_NAME_"]);
    angular.extend(this, $controller('GenericListController', {$scope: $scope}));
});

The most interesting fact is that GenericListController is also using the same $scope.localisation array and it has not problems with it!

The load order is:

  1. app.js
  2. service.js
  3. genericController.js
  4. controller.js

Upvotes: 0

Views: 2120

Answers (1)

nitin
nitin

Reputation: 3787

Instead of copying yr results to $rootScope, you should directly read from service.

why ? Yr $rootScope lives throughout yr application life, it sits right above all yr controller's scope, so its better to keep it lightest.

code :

app.factory("StringsTranslationService", function($http,$q) {

  var StringsTranslationService={};
  var data='';
  var dataReady=false;

  StringsTranslationService.getData = function (locale) {

    var deferred= $q.defer();
    $http({
      method:"GET",
      url:'public/resources/strings_'+locale+'.txt'
    })
    .success(function(result){
      deferred.resolve(result.data[0]);
    })
    .error(function(error){
      deferred.reject(error);
    })
    return deferred.promise;

 };

 return StringsTranslationService;
});

Update yr app.run

app.run(function(StringsTranslationService){

   //call service & read data
    StringsTranslationService.getData('en')
     .then(function(data){
          StringsTranslationService.data=data;
          StringsTranslationService.dataReady=true;

          //if you really want it add to rootScope
          //$rootScope.localisation=data;
      },
      function(error){
          //handle error here
      })  

});

Inside yr controller check if data is ready & then read

app.controller('ListController', function ($scope, StringsTranslationService){

    if(StringsTranslationService.dataReady===false){
      $scope.loading=true;
    }
    else {
       $scope.loading=false;
       $scope.data=StringsTranslationService.data;
    }


});

This way you will only do a single call to fetch data & it will b available across app.

Upvotes: 1

Related Questions