Ivan Proskuryakov
Ivan Proskuryakov

Reputation: 1732

AngularJS set Variable on Application .run method. Later use in controller, service, html

I need to set global config variable for my App populated with $http.get(url);

    .run(['$http', '$rootScope','rootService', function($http, $rootScope, rootService) {

    rootService.getApplicationConfig().success(
        function(data, status) {
            $rootScope.appSettings = data;
        }
    );

I can use it in html with {{appSettings.SomeValue}}. The problem that .run method executes after .config. And in controllers appSettings is undefined.

How can I get this working in controllers? Or make global variables, which would be populated only once startup.

Upvotes: 2

Views: 11825

Answers (4)

E. Mourits
E. Mourits

Reputation: 285

Note: Don't use .run(). The method is runs async and you won't always have your data!

Use the value provider with an AppController.

Example:

Declaring a value (do this in your app.js):

angular.module('app', ['ui.router'])
.value('appSettings', { myValue: undefined })

appSettings is now an injectable service. Use like this:

angular.module('ctrls.myCtrl', [])
.controller('myCtrl', ['appSettings', function(appSettings) {
    console.log(appSettings.myValue);
}]);

Setting the value from a server resource when the application starts.

Declare the AppController (i usually do this in my app.js):

.controller('appCtrl', ['rootService', 'appSettings', function (rootService, appSettings) {
var vm = this;
vm.loaded = false;

if (appSettings.myValue == undefined) {
    rootService.getApplicationConfig().success(
       function(data, status) {
           appSettings.myValue = data;
           vm.loaded = true;
       }
   );
}}]);

In the body of your main html page (the boot css class shows some sort of loading screen):

<div ng-controller="appCtrl as vm">
    <div class="boot" ng-show="!vm.loaded"></div>
    <div ng-if="vm.loaded" ui-view="main" role="main" class="main"></div>
</div>

The rest of the controllers in your application are loaded in the ui-view="main", only after the appCtrl has loaded your server settings. This way you always have your appSettings.

Upvotes: 1

Whisher
Whisher

Reputation: 32726

DONT USE THIS CODE

It's very tricky and I never put this code in my app ^^ The only way I found is:

'use strict';
            angular.module('app', [])
            .config(function () {

           })
           .run(function($rootScope,$timeout,Myconfig){
                $rootScope.config = {};
                Myconfig.get().then(function(data){   
                   $rootScope.config = data;
               });
           })
           .factory('Myconfig', function ($http,$q) {
                return {
                    get : function() {
                        var deferred = $q.defer();
                        $http.get('config.json')
                            .success(function (response) {
                                deferred.resolve(response);
                            })
                            .error(function(data, status, headers, config) {
                                deferred.reject([]);
                        });
                        return deferred.promise; 
                   } 
                }
          })
          .controller('MainCtrl',function($scope){
            $scope.$watch('config',function(){
                console.log($scope.config);
            });

          });

If you get an eye on the console you can realize you can't use this code in prod at least I don't find any any to use a promise to retrieve a config from the server.

UPDATE I suppose it's your server so write server side a config js like

var config = {prop:1};

include in your page and than simply do

app.constant('CONFIG',config)

UPDATE

pseudo code

The only sensible thing I think of:

$routeProvider.when('/', {
    controller: 'MyCtrl',
    resolve: {
        config: function(rootService) {
            return rootService.getApplicationConfig()
        }
    }
})

app.controller('MyCtrl', function ($scope,MyService,config) {
    MyService.set(config);       
});
app.controller('MyCtrl', function ($scope,MyService) {
    MyService.get();       
});

Upvotes: 1

Ivan Proskuryakov
Ivan Proskuryakov

Reputation: 1732

Finally found an answer how to maker JSON only once!

in your app.js, where app = angular.module add

    $provide.factory('appConfig', function ($q,rootService) {
        return rootService.getApplicationConfig();
    });

rootService.js

angular.module('projectApp').service('rootService', ['$http','$routeParams','API_URL',function ($http, $routeParams, API_URL) {
    return {
        getApplicationConfig: function() {
            var url = API_URL+'/config/settings.json';
            console.log(url);
            return $http.get(url);
        },
    };

}]);

finally in your controller do like this

angular.module('projectApp').controller('MainCtrl', ['$location','$scope','$routeParams','rootService','appConfig', function ($location, $scope, $routeParams, rootService, appConfig) {

    $scope.content = false;
    appConfig.success(
        function(data, status) {
            console.log(data.time);
            $scope.content = JSON.parse(data.config_homepage).content
        }
    );

}]);

On server side I push time to my JSON. Each time I use "appConfig" it show the same time. Which means that request goes to the server only once.


If someone have better solution, please post it as answer

Upvotes: 0

Ivan Proskuryakov
Ivan Proskuryakov

Reputation: 1732

Found solution with "value"

    .value('appConfig',{
            apiUrl: '/api',
            settings: null
    })

    .run(['$http', '$rootScope','rootService','appConfig', function($http, $rootScope, rootService,appConfig) {

        console.log(appConfig);
        appConfig.settings = 'we can change it';
        console.log(appConfig);


}])

Upvotes: 0

Related Questions