Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them, it only takes a minute:

I'm working on a SPA with AngularJS. After the sign in, a cookie is created with a token and a user object is stored in $rootScope.user which is conveniently accessible from various controllers as they are dynamically loaded.

The application works fine when I use it normally and navigate around.

When I refresh a page with F5, angular is reloaded and the module run() method checks if the cookie exists and reloads the user from the server into $rootScope.user. However, while this is happening, another controller is already expecting $rootScope.user to have a user.

How can I prevent controller initialization before my $rootScope.user is ready and loaded. If can, of course, check in the controller if there is a user loaded in $rootScope. But if there isn't, how can $rootScope invoke a controller to carry out some initialization?

Here is code in app.run():

app.run(function ($rootScope, $location, $cookies, appServices) {

    var token = $cookies.get('UserToken');
    if (token) $rootScope.token = token;

    $rootScope.$on("$routeChangeStart", function (event, next, current) {

        // Get user from server if token is there but no user
        if ($rootScope.user == null) {
            if ($rootScope.token) {
                appServices.getUserByToken(token).then(function (d) {
                    if (d.Code == 1) {
                        $rootScope.user = d.ReturnObj;
                        if ($rootScope.user != null && next.templateUrl == "web/views/signin.html") $location.path("/dashboard");
                    } else $rootScope.goSignin(next.templateUrl);
                });
            }
            else $rootScope.goSignin(next.templateUrl);
        }
    });
})

And here is sample code in a controller that is dynamically loaded:

app.registerCtrl('userdetailCtrl', function userdetailCtrl($scope, $http, $rootScope, $routeParams, appServices, $location, validationService) {

  $scope.getOffices=function()
    {
      appServices.getOffices({ ID: $rootScope.user.OrgID, Token: $rootScope.token }).then(function (d){
      if(d.Code==1){$scope.office = d.ReturnObj;}});
    }

  $scope.getOffices();

});

The getOffices() function requires $rootScope.user.OrgID, which is not found as $rootScope.user is not yet loaded.

Any ideas?

share|improve this question
    
put a watch on it? – Jorg Sep 23 at 12:24
    
Can you elaborate as to how I would do this? Am a bit new with Angular. – navigator Sep 23 at 12:57
    
sure, i added an answer – Jorg Sep 24 at 7:23

2 Answers 2

You can do several things, here's an example of two of these. Check the console in this fiddle

1. Watch the variable for changes:

The first is watching $rootScope.user for changes in your controller:

App.run:

$timeout(function() {
    $rootScope.user = 'user';
}, 500)

in your controller:

$rootScope.$watch('user', function(newVal, oldVal) {
   console.log(newVal, $rootScope.user); 
});

You can 'unwatch', too, if you don't want to keep executing code every time the user variable changes.

2. Emitting an event

The second is emitting an event, and catching it where required, like this:

App.run:

$timeout(function() {
    $rootScope.user = 'user';
    $rootScope.$broadcast('userEvent');
}, 500)

Your controller:

$rootScope.$on('userEvent', function() {
    console.log($rootScope.user);
});
share|improve this answer
    
Thanks! This looks like a good solution. But I don't want to implement a $watch or $broadcast simply for the rare chance of a browser page refresh. This would mean I would need to write mostly unnecessary code to check for $rootScope in many controllers. What I was looking for is a way to halt controller initialization until certain conditions were met. – navigator Sep 24 at 14:37
    
Your design might need tweaking then. Maybe a user service instead of a rootscope variable, and chain the promises? – Jorg Sep 24 at 20:27

Not sure if this will work in your situation, but

$rootScope.$on('$includeContentLoaded', function () {
    //fetch user here
}

solved a similar issue that I had

share|improve this answer
    
I'm not using ng-include. Views and controllers are loaded via ng-view and routing. – navigator Sep 23 at 12:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.