0

i am calling a function from ng class because i want to return class name dynamically based on price.

i have 6 data and function suppose to call 6 times but when i run the code then i saw it is calling 12 times.....anyone can see the code and tell me why the function is getting called 12 time instead of 6.

<div ng-app="myApp">
  <ul ng-controller="MyController">
    <li ng-class="setColor(item.price)" ng-repeat="item in products">{{item.name}} &mdash; {{item.price}}</li>
  </ul>
</div>


var myApp = angular.module('myApp', []);

myApp.controller('MyController', function MyController($scope) {

$scope.setColor = function(price) {

     alert(price);
}   

  $scope.products = [
    {
        'name' : 'Xbox',
        'clearance' : true,
        'price' : 30.99,
    },
    {
        'name' : 'Xbox 360',
        'clearance' : false,
        'salesStatus' : 'old',
        'price' : 99.99,
    },
    {
        'name' : 'Xbox One',
        'salesStatus' : 'new',
        'price' : 50,
    },
    {
        'name' : 'PS2',
        'clearance' : true,
        'price' : 79.99,
    },
    {
        'name' : 'PS3',
        'salesStatus' : 'old',
        'price' : 99.99,
    },
    {
        'name' : 'PS4',
        'salesStatus' : 'new',
        'price' : 20.99,
    }
    ]
})

here is jsfiddle https://jsfiddle.net/tridip/ob8jh2o7/1/

UPDATE : My Objective

if price less than 50 then item color should be red. if price more than 50 then item color should be yellow and if price more than (50+(50*60/100)) then item color should be green. now tell me how could i achieve it with less iteration. guide me with best approach to complete it.

thanks

if fix it. here is my new fiddle link https://jsfiddle.net/tridip/ob8jh2o7/22/

Mou
  • 15,673
  • 43
  • 156
  • 275
  • This is how angular works. It will execute that every digest cycle and continue to execute it until it detects no changes. That means at least twice per row and up to 10x per row per digest cycle. What is the problem? 12 iterations is nothing. If you have thousands (even hundreds) of these rows, ng-repeat is notoriously slow, you should consider one-time binding them instead but they will never be updated. your json can't change or it wont be reflected... http://blog.thoughtram.io/angularjs/2014/10/14/exploring-angular-1.3-one-time-bindings.html – Charlie Martin Apr 08 '16 at 18:11

3 Answers3

2

Based on Using ng-class with a function call - called multiple times

You can try something like this if you are just modifying the class:

var colourMap = {
    "30.99": "speciality1Class",
    "99.99": "speciality2Class",
    "50": "speciality3Class",
    "79.99": "speciality4Class",
    "20.99": "speciality5Class"
};


$scope.setColor = function(price) {
    return colourMap[price];
}   

fiddle: https://jsfiddle.net/ob8jh2o7/11/

However, if you are using an alert or log it is going to be called all those times because angulars use of dirty checking. If you are trying to fire an alert though, I would not use ng-class. You can read more about angulars dirty checking here - https://docs.angularjs.org/guide/scope#scope-life-cycle .

Community
  • 1
  • 1
ajmajmajma
  • 13,712
  • 24
  • 79
  • 133
  • i check your js fiddle and put alert and notice iteration happen 12 times instead of 6.....but do not understand the reason. – Mou Apr 08 '16 at 17:58
  • see my update and My Objective area and answer accordingly. – Mou Apr 08 '16 at 18:07
  • @Mou if you are putting the alert in ng-class evaluation it will fire 2 times because of the dirty checking, I would recommend reading that linked post for a bit more detail on the dirty checking if you are interested. As for your updated objective, you can just do some if/else. – ajmajmajma Apr 08 '16 at 18:21
  • And again, if you need to execute a function on each item in the repeat **don't evaluate it in ng-class**, use ng-init or something else. – ajmajmajma Apr 08 '16 at 18:26
  • we can not set css class if i use ng-init. i am not sure if i could fullfil my objective by ng-init. would u show me how to accomplish my goal using ng-init which set class dynamically. – Mou Apr 08 '16 at 18:29
  • @Mou you can use both `ng-class` for the class application, and `ng-init` to call the function. Again, if you don't want something evaulated multiple times like that **don't evaluate it in ng-class**. You can use class and init on the same line. furthermore your objective is now a brand new question. – ajmajmajma Apr 08 '16 at 18:54
1

Angularjs uses a dirty-check approach, so it need to call all the filters to see if exists any change. After this it detect that have a change on one variable(the one that you typed) and then it execute all filters again to detect if has other changes.

The first call is from the watchers that are detecting the change. Because there is one then they need to be called again to see if is there news changes because a watcher can make changes.

Alien
  • 3,658
  • 1
  • 16
  • 33
  • in my code when ng-repeat will execute then how many time control will iterate in loop. if there is 6 data in array then ng-repeat should repeat 6 times. this is not clear what is dirty check from your explanation and also for why dirty check the iteration will occur twice means 12 times instead of 6? help me to understand this. – Mou Apr 08 '16 at 17:56
  • see my update and My Objective area and answer accordingly. – Mou Apr 08 '16 at 18:07
0
   <li ng-class="{red : item.price <= 50 , yellow: item.price >  50 && item.price <= 50 + 50*0.6, green: item.price > 50 + 50*0.6}" ng-repeat="item in products track by $index">{{item.name}} &mdash; {{item.price}}</li>

Edited Fiddle working: https://jsfiddle.net/ob8jh2o7/21/