简体   繁体   中英

When does ngClass evaluate functions / How to mimic this in custom directive

I'm hoping someone can offer some Angular insight that I am sorely lacking right now.

ngClass allows you to add/remove a class depending on some function. For example, if I write:

<div ng-class="{'some-class' : myFunction()}"> </div>

then .some-class will be added/removed if myFunction() evaluates to truthy or falsey. What is especially good is that I don't need to worry about this function getting called anywhere else in my code for the expression to evaluate. ngClass just takes care of keeping the class up to date with the current return value of myFunction().

So my first question is how does ngClass determine when to check if the return value of myFunction() has changed? Does it check myFunction() on every digest loop? Something presumably has had a watch set on it, but what is being watched? I tried reading the code for ngClass but I didn't have enough background knowledge to get a handle on how it's implemented.

The reason I want to know this is that I want to mimic this behaviour in a custom directive. So in my app I have something like the above ngClass. myFunction() is sitting on the main controller for my page, but it does a bunch of direct DOM manipulation so it shouldn't be there. I'd like to take myFunction() out of the controller and move it into a custom directive, but if I do that then I need some way to repeatedly check against this function in order to set classes. I would like to be able to do something like this:

app.directive('myDirective', function () {
  return {
    restrict: 'A,
    link: function (scope, elem, attrs) {
      function myFunction() {//...}

      // I want this to be checked at the
      // same frequency that ngClass is checked
      // Is that each digest cycle?

      if (myFunction()) {
        elem.addClass('some-class');
      } else {
        elem.removeClass('some-class');
      }
    }
  }

Obviously this isn't going to work. It's only going to run when the directive gets linked. So how can I watch myFunction() for changes?

I would use .$watch() , which evaluates the initial argument during every $digest cycle, and invokes a listener (the second argument) once during initial load and subsequently, every time the evaluation of the initial argument returns a different value than the previous.

See https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch .

Base on the psuedo-code you provided (actual code would have been nicer for testing purposes :-) here's an example of what you should do:

app.directive('myDirective', function () {
  return {
    restrict: 'A',
    link: function (scope, elem, attrs) {
      scope.$watch(function() {
         // .. this is your "myFunction()"
         return result;
      }, function(newResult) {
        if (newResult) {
          elem.addClass('some-class');
        } else {
          elem.removeClass('some-class');
        }
      });
    }
  }
}  

Also, make sure you have the closing quote on the 'A' value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM