Why is ng-style function applied twice?

后端 未结 2 1019
北恋
北恋 2020-12-06 19:20

I\'ve got an angular app like:

angular.module(\'ngStyleApp\', [])

.controller(\'testCtrl\', function($scope) {
   $scope.list = [1,2,3];
   $scope.getStyles         


        
相关标签:
2条回答
  • 2020-12-06 20:00

    The Angular $digest cycle evaluates the ngStyle attribute at least twice - once to get the value and once to check if it has changed. It actually keeps iterating until the value settles so could potentially check the value many times.

    Here's a picture to illustrate this:

    enter image description here

    Here is a good blog post illustrating this: angular digest blog

    Actually, try this quote from StackOverflow that says it very well:

    When watched functions are evaluated (during $digest) if any of them have changed from the previous $digest then Angular knows that change might ripple through to other watched functions (perhaps the changed variable is used in another watched function). So every watch is re-evaluated (also called dirty processing) until none of the watches results in a change. Thus typically you'll see 2 calls to watched functions per digest and sometimes more (up to 10- at 10 loops through it gives up and reports an error saying it can't stabilize).

    (Reference here)

    0 讨论(0)
  • 2020-12-06 20:16

    This is the code of the ngStyle directive:

    var ngStyleDirective = ngDirective(function(scope, element, attr) {
      scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
        if (oldStyles && (newStyles !== oldStyles)) {
          forEach(oldStyles, function(val, style) { element.css(style, '');});
        }
        if (newStyles) element.css(newStyles);
      }, true);
    });
    

    Notice that there is a scope.$watch for attr.ngStyle, that watch is what is making it trigger twice.

    For instance, if you try to do the same thing using ngInit, you will notice that the function only gets called once. Now, lets have a look at the code of the ngInit directive, it looks like this:

    var ngInitDirective = ngDirective({
      priority: 450,
      compile: function() {
        return {
          pre: function(scope, element, attrs) {
            scope.$eval(attrs.ngInit);
          }
        };
      }
    });
    

    Notice that there is no watch in this directive.

    0 讨论(0)
提交回复
热议问题