Search code examples
javascriptangularjsangularjs-scopeangularjs-serviceangularjs-routing

Trying to persist data across controllers using Angular rootScope, but always getting undefined


I have an administrator login page. When a user successfully logs in as an admin, I want to display at the top of all pages the user visits:

<!-- nav bar -->
<div>
    <span ng-show="$root.isAdmin">(ADMIN)</span>
</div>

I tried using $rootScope to accomplish this, but I keep getting undefined:

// controller for logging in
app.controller('AdminLoginCtrl', [ '$rootScope', '$scope', 'stateParams', 'loginService', function($rootScope, $scope, $stateParams, loginService) {
    loginService.success(function() {
        $rootScope.isAdmin = true;
        console.log($rootScope.isAdmin);   // returns true
        $location.path("/login_success");
    });
}]);

// some other controller AFTER user is logged in as admin
app.controller('BlahCtrl', ['$rootScope', '$scope', function($rootScope, $scope) {
    console.log($rootScope.isAdmin);   // returns 'undefined'
});

There have been some other similar topics, but don't apply to me:

(I don't have an injection problem):

$rootscope value undefined in Controller

(My other controller is definitely being called AFTER login, so $rootScope.isAdmin should be set):

AngularJS - Cannot access RootScope

(I don't have an ordering problem):

Angular $rootScope.$on Undefined

The other solution could be to not use $rootScope at all, and just use a service to hold shared data. But if I have 10+ controllers, is it acceptable to do this in each:

app.controller('...', ['$scope', 'checkAdminService', function($scope, checkAdminService) {
    $scope.isAdmin = checkAdminService.getIsAdmin()
}]);

Then:

<span ng-show="isAdmin">(ADMIN)</span>

Is this acceptable or more cumbersome? And for completeness sake, why doesn't $rootScope solution work at all?


Solution

  • It's indeed a bad practice using the $rootScope. The best solution is what you propose yourself to create a service storing the information you want to share between different controllers. It is no problem to call this method on several locations...

    Why don't you define a separate controller for the top-part of your page which will be the only one verifying whether the user is an admin? The other part of your page can be controller by different controllers.

    This example will explain how to use several controllers, but of course this can also be achieved via Routers.