0

Why ng-class don't work with scope var's

sheikContolls.controller('MainPageController', ['$scope', 'authService',
    function ($scope, authService) {
       if(!authService.isAuthenticated()){
            $scope.class1 = "good";
       }
       else {
            $scope.class1= "bad";
       }
    }
    ]);

HTML:

<div class="demo" ng-class="class1"></div>

When you first start the class is added and we have class="demo good", but if then isAuthenticated() return true, class don't change, why ?? The same with next HTML:

<div class="demo {{class1}}"></div>

If i make a function - all work perfect.

<div class="demo" ng-class="getClass()"></div>
hoeni
  • 3,031
  • 30
  • 45
  • You must be having [some kind of directive (`ng-if,ng-repeat etc...`) that creates a child scope](http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs) wrapping this div. – PSL May 07 '15 at 15:36
  • Can you show us `getClass`? – Explosion Pills May 07 '15 at 16:17

2 Answers2

1

The code in the controller is called only once when the controller is instantiated and never again later, so it does never check authService.isAuthenticated() again.

When you use a function in your HTML-Code that function is called regularely and watched for its result, so later changes will be applied.

You could move the detailed check in the controller and call it from the HTML for some encapsulation:

sheikContolls.controller('MainPageController', ['$scope', 'authService',
   function ($scope, authService) {
       $scope.isAuthenticated = function(){
           return authService.isAuthenticated();
       };
   }
]);

<div class="demo" ng-class="{good: isAuthenticated(), bad: !isAuthenticated() }"></div>
hoeni
  • 3,031
  • 30
  • 45
  • When you use `ng-class="class1"` then also `class1` getter is created automatically and being watched upon. So it really makes no difference calling `getClass()` or `isAuthenticated()`. So if at all the class1 property on the scope is updated at any time, next digest cycle will update ng-class expression too. Actually i feel issue might be hidden behind some scoping issue? But you make a good point where OP might not be calling `isAuthenticated()` as he thinks he does or at least he is not showing us that part. – PSL May 07 '15 at 15:53
  • @PSL I tried to say this in my answer but may not have been eloquent about it. `class1` never changes in his current app so the fact that it is watched or that the digest cycle occurs doesn't mean anything -- it will still be `"good"`. The digest cycle would have to run `isAuthenticated` *again* which requires binding it to the scope. – Explosion Pills May 07 '15 at 15:56
  • @ExplosionPills yeah i agree, actually it is confusing that is op expecting that isAuthenticated (`but if then isAuthenticated() return true`) will be called automatically by placing it in the constructor directly. Bu OP says it works when used in `getClass()` is OP just returning the class or evaluating the expression (as you are showing)? There might be some relevant parts missing in the question? – PSL May 07 '15 at 15:59
  • @psl: I personally don't like exposing logic like authentication directly to the view, but rather encapsulate in the controller, but that's just a matter of personal taste. Regarding functionally that's just a NOP more, but brings in some flexibility e.g. when the signature changes :-) – hoeni May 07 '15 at 16:01
  • @hoeni Placing `isAuthenticated()` service call in a function being watched (whether directly in the view or in the ng-class function expression) could turn out really expensive based on what it is doing. I personally would always set it on the property and probably what op is missing is a promise pattern from isAuthenticated(), seems like it is an async operation. like `
    `
    – PSL May 07 '15 at 16:03
  • no, controller run tiwce, this is don't all code in second time isAuthenticated() == true. Yes function getClass work perfect, but WHY class don't change with variable only with function ? i want change class with variable in scope, not using the function! – Alexandr Kovalenko May 07 '15 at 16:56
1

authService.isAuthenticated is not bound to the scope, and the controller definition function only runs once so initially class1 is good, but that functionality never runs again.

You will have to bind isAuthenticated to the scope in some way for this to work. I might consider an alternate solution like binding to a value on authService that is updated after authorization is done, but in the meantime you can do this:

$scope.getClass = function () {
    if (authService.isAuthenticated()) {
        return "bad";
    }
    return "good";
};

http://plnkr.co/edit/1xFRoTusNLHXeIhosGOp?p=preview

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • no, controller run tiwce, this is don't all code in second time isAuthenticated() == true. Yes function getClass work perfect, but WHY class don't change with variable only with function ? i want change class with variable in scope, not using the function! – Alexandr Kovalenko May 07 '15 at 16:54