1

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?

fanhats
  • 777
  • 2
  • 10
  • 20
  • how about your ng-app goes ? – underscore Feb 16 '15 at 17:24
  • I think you should avoid using rootScope to handle shared data. It feels too much like polluting the global context. I use a service to handle the data, much like you showed. I think it's more "angularesque": `app.controller('...', ['$scope', 'checkAdminService', function($scope, checkAdminService) { $scope.isAdmin = checkAdminService.getIsAdmin() }]);` It's more SOC and makes for easier testing, should you choose to go that route – Brennan Feb 16 '15 at 17:27
  • When scope2 nests scope1, for read-access you can address all variables from scope1 in scope2. You dont need anything else. You should not use $root, $rootScope for reading variables. Look here 3 controllers accesses variable/function from $rootScope: http://plnkr.co/edit/F5rQGqrnuSgo91dgr47l – Petr Averyanov Feb 16 '15 at 18:00

3 Answers3

1

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.

1

What if you replace the $rootScope that you're passing around with a special-purpose angular value that you can register at startup and pass around as needed?

http://plnkr.co/edit/r6kdouh0BbnYA4DmEcEM?p=preview

angular
    .module('app')
    .value('userProfile', userProfile);

function userProfile() {
  var userProfile = {
    isAdmin: false
  };
  return userProfile;
}

/////////////////

angular
    .module('app')
    .run(run);

run.$inject = ['userProfile', 'userAuthService'];
function run(userProfile, userAuthService) {
  userAuthService.isUserAdmin().then(function(result) { userProfile.isAdmin = result; });
}   
RJB
  • 2,063
  • 5
  • 29
  • 34
0
angular.module('yourmodule', []) 
  .run(['$rootScope', function($rootScope) {
    $rootScope.isAdmin = true;
])
Seth Koch
  • 3
  • 1