Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs function inside ng-repeat called too many times

I've got a function in my controller very easy that just stamp a console.log. I need to conditioning a button using a function but inside the ng-repeat the controller repeats everything many times! Is it normal? Is it possible avoid this? Thanks. An example here http://plnkr.co/edit/sME67gQEZQSLI9FOwEAG?p=preview

relative code:

<!DOCTYPE html>
<html>

  <head>
    <script data-require="[email protected]" data-semver="1.4.5" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-app="DigestApp">
    <div ng-controller="UserCtrl as uc">
      <h1>Please open the console to see</h1>
      <ul>
        <li ng-repeat="user in uc.users" ng-class="uc.userClasses(user)">
          {{user.name}}
          <button ng-if="uc.isUserEnabled(user)"
                  ng-click="uc.disableUser(user)">Disable</button>
        </li>
      </ul>
    </div>
  </body>

</html>

javascript:

angular.module("DigestApp", [])

.controller('UserCtrl', function(User) {
  var vm = this;

  vm.users = User.list();

  vm.isUserEnabled = function(user) {
    console.log('isUserEnabled');
    return user.active;
  };

  vm.userClasses = function(user) {
    console.log('userClasses');
    return []
      .concat(user.active ? ['user-active'] : [])
      .concat(user.loggedIn ? ['user-logged-in'] : [])
      .concat(user.isMe ? ['user-is-me'] : [])
      .join(' ');
  };

  vm.disableUser = function(user) {
    user.active = false;
  };
})

.factory('User', function() {
  return {
    list: function() {
      return [{
        name: "me",
        active: true,
        loggedIn: true,
        isMe: true
      }];
    }
  };
});
like image 638
Atlas91 Avatar asked Jun 24 '26 10:06

Atlas91


1 Answers

Yes, this is normal. There is no way that angular can tell whether the result of the function will have changed, so it calls it on every digest loop. If you want to avoid that you should calculate the value once and set the result as an attribute on the user object.

<li ng-repeat="user in uc.users" ng-class="user.classes">
      {{user.name}}
      <button ng-if="user.active"
              ng-click="uc.disableUser(user)">Disable</button>
</li>

and in the controller add some code to precalculate a user.classes attribute on each user object (and to update it when you change the state of the model).

like image 190
Duncan Avatar answered Jun 25 '26 23:06

Duncan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!