MChan
MChan

Reputation: 7182

AngularJS running code in app.run()

I am trying to run the following code before any of my AngularJS app controllers, directives run, but unfortunately the app main page controller loads before this code finish executing, so I was wondering if there is a way to ensure that all my app controllers, directives won't run / load before this code finish completely? Thanks

  myApp.run(['TokenSvc',function (TokenSvc) {

        TokenSvc.getToken().then(function(serverToken){
            console.log('Got it...');
        }, function(status){
            console.log(status);
        });    
  }]);

Upvotes: 0

Views: 952

Answers (2)

user128268
user128268

Reputation: 126

Most commonly you'll see resolve in the ng-route or ui-router $state definition used for this concern, but that can be problematic. If the resolution takes a while, the user will just be staring at a blank screen. Of course, you can mitigate this problem by using an interceptor to display a loader, but I'd argue that that's outside the intended utility of interceptors.

I like to use something to manage the initialization promise(s), and inject that thing into top-level Controllers (i.e. either a Mediator or Observer pattern):

(function () {
    function UserInfoLoader($q, facebookService, githubService) {
        var _initPromise = null;

        function initialization() {
            var deferred = $q.defer(),
                _initPromise = deferred.promise,
                facebookLoading = facebookService.somePromiseFunc(),
                githubLoading = githubService.somePromiseFunc();

            $q.all([facebookLoading, githubLoading])
                .then(function (results) {
                    // do something interesting with the results
                    deferred.resolve();
                    // set the promise back to null in case we need to call it again next time
                    _initPromise = null;
                });

            return promise;
        }

        this.initialize() {
            // if there's already an initialization promise, return that
            return _initPromise ? _initPromise : initialization();
        }
    }

    angular.module('myApp').service('userInfoLoader', UserInfoLoader);
}());

This is great, because you can have multiple Controllers depend on the same workflow logic and they'll only produce one promise.

(function () {
    function UserProfileController($scope, userInfoLoader) {
        $scope.loading = true;

        function load() {
            userInfoLoader.initialize().then(function () {
                $scope.loading = false;
            });
        }

        load();
    }

    function UserMessagesController($scope, userInfoLoader) {
        // same sort of loading thing
    }

    angular.module('myApp')
        .controller('userProfileController', UserProfileController)
        .controller('userMessagesController', UserMessagesController)
    ;
}());

To borrow from Mr. Osmani's book linked above, the loader service is like an air traffic controller. It coordinates the schedules of and passing information between multiple "airplanes", but they never have to talk to each other.

Another approach that I've seen is to use a FrontController, usually added on the body element, that manages a global loader, showing it during long-running async operations. That one's pretty simple, so I won't write it all out.

Upvotes: 2

csbenjamin
csbenjamin

Reputation: 356

Do the fowllowing in each route:

$routeProvider.when("/your/path", {
    templateUrl: "template/path",
    controller: "controllerName",
    resolve: {
            getToken: ['TokenSvc',function (TokenSvc) {
                    return TokenSvc.getToken();
            }]
    }
});

You need that the getToken method return always the same object. Something like this:

obj.token = null;
obj.getToken = function(){
    if(!obj.token){
        var deferred = $q.defer();
        obj.token = deferred;
        deferred.promise.then(function(serverToken){
            console.log("Got it. The token is ",serverToken);
        }, function(status){
            console.log("something is wrong ", status);
        });
        $http.get("url/to/token")
        .success(function(data){
            deferred.resolve(data);
        })
        .error(function(data, status){
            deferred.reject(status);
        });
    }

    return obj.token.promise;
}

Upvotes: 1

Related Questions