Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is ng-style function applied twice?

I've got an angular app like:

angular.module('ngStyleApp', [])

.controller('testCtrl', function($scope) {
   $scope.list = [1,2,3];
   $scope.getStyles = function(index) {
       console.log('getting styles for index ' + index);
       return {
           color: 'red'
       };
   };
});

with the corresponding markup:

<div ng-app="ngStyleApp">
    <ul ng-controller="testCtrl">
        <li ng-repeat="value in list" ng-style="getStyles($index)">
            {{value}}
        </li>
    </ul>
</div>

The visible output is three red list items, as expected. But the statement is logged to the console a total of 6 times, implying that the view is rendered twice:

getting styles for index 0
getting styles for index 1
getting styles for index 2
getting styles for index 0
getting styles for index 1
getting styles for index 2

Why?

  • JSFiddle
like image 671
calebds Avatar asked Sep 19 '14 03:09

calebds


People also ask

Can we use two ngStyle in angular?

With style binding we can set only a single style, however to set multiple styles we can use ngStyle directive.

Why do we use ng style?

NgStyle gives you fine grained control on individual properties. But if you want to make changes to multiple properties at once, creating a class which bundles those properties and adding the class with NgClass makes more sense.

How do I apply two styles in ngStyle?

The ngStyle Directive To add multiple styles, we can pass an object where keys will be the CSS property names and the values will be respective expressions. We can also define the object in the component and use it in the template.

What is ng style?

NgStylelink An attribute directive that updates styles for the containing HTML element. Sets one or more style properties, specified as colon-separated key-value pairs. The key is a style name, with an optional .


2 Answers

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)

like image 93
Caspar Harmer Avatar answered Oct 20 '22 22:10

Caspar Harmer


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.

like image 22
Josep Avatar answered Oct 20 '22 22:10

Josep