Search code examples
javascriptangularjscontrollerpromiseresolve

AngularJS load controller after resolve doesn't work


Goal: In my application every controller should be initialized after a user has a session / is logged in, because in this controller I use the data of logged in user.

Code:

app.js

    app.run(function($q, $rootScope, AuthSvc){
    $rootScope.ajaxCall = $q.defer();
    AuthSvc.reloadSession().then(
        function(response){
            if(response!=null && response!=undefined){
                $rootScope.activeUserSession = response;
                $rootScope.ajaxCall.resolve();
            }else{
                $rootScope.activeUserSession = null;
                $rootScope.ajaxCall.reject();
            }
        });
    return $rootScope.ajaxCall.promise;
});

routes.js

.config(['$routeProvider',
    function($routeProvider) {
        $routeProvider.
            when('/timeTracking', {
                templateUrl: 'partials/timeTracking/projectView.html',
                controller: 'timeTrackingController',
                resolve: {
                    response: function($rootScope, $q) {
                        var defer = $q.defer();
                        $rootScope.ajaxCall.promise.then(
                            function(){
                                defer.resolve();
                                return defer.promise;
                            });
                    }
                }
            }).

Problem: Controller gets initialized sometimes before the user has a session, I do not understand why.

Sorry I am new to Angular and my english is also crap, so I hope nevertheless you can understand what is my problem.


Solution

  • I think placing your session reload into the app.run is not the right place. Add it directly to resolve and checkout the docs for $q to learn how promises are working.

    Because you can't call a promise or defer. You need to call a function that's returning a promise then you can add your then method to do your stuff after the promise is resolved.

    Please have a look at the demo below or here at jsfiddle.

    It's just an asynchronous method with $timeout to simulate the auth because I don't have a backend to add in the demo.

    You can add your AuthSvc directly into resolve.

    angular.module('demoApp', ['ngRoute'])
    .controller('timeTrackingController', function($scope, response) {
        $scope.data = response;
    })
    .factory('authService', function($q, $timeout) {
        return {
            reloadSession: function() {
                var deferred = $q.defer();
                $timeout(function() {
                    // just simulate session reload
                    // real api would to the job here
                    console.log('resolved defer now!!');
                    deferred.resolve({dummyData: 'hello from service'});                
                }, 1000);
                
                return deferred.promise;
            }
        }
    })
    .config(['$routeProvider',
        function($routeProvider) {
            $routeProvider.
                when('/timeTracking', {
                    templateUrl: 'partials/timeTracking/projectView.html',
                    controller: 'timeTrackingController',
                    resolve: {
                        response: function(authService) {
                            return authService.reloadSession().then(function(data) {
                                return data;
                            })
                        }
                    }
                })
            .otherwise('/timeTracking');
        }]);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.3/angular.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.3/angular-route.js"></script>
    
    <div ng-app="demoApp">
        <script type="text/ng-template" id="partials/timeTracking/projectView.html">
            project view: {{data | json}}
        </script>
        <div ng-view=""></div>
    </div>