Question

It seems like ngRepeat triggers the watches on any list item after changing one of them. I'm already using track by so that doesn't seem to help.

Here's my template:

div(ng-repeat="poll in polls track by poll._id")
  poll(poll="poll")

.poll
  .title(ng-if="!poll.closed") {{poll.title}}
  .btn(ng-click="poll.closed = true") Change poll
  {{someExpensiveComputation(poll._id)}}

javascript:

.directive('poll', function($rootScope, $modal) {
  return {
    replace: false,
    restrict: 'E',
    scope: {
      poll: '='
    },
    templateUrl: '/tmpl/poll',
    link: function($scope, elem, attrs) {
      $scope.someExpensiveComputation = function (id) { ... }
    }
  }
});

It seems like whenever a poll item is changed the someExpensiveComputation function runs for all the polls, and 3x each time. How do I get it to not do that? It should only trigger the watchers for that directive. I think that should be possible.

Thanks.

Était-ce utile?

La solution

All watch-expressions are processed (evaluated) multiple times in every $digest loop.
So, it is a good practice to keep the watch-expression as simple as possible (in terms of computational complexity).

(BTW, using {{...}} in your view creates a watch.)

If someExpensiveComputation() is...computationally expensive, you don't want to evaluate it every time, but only when it might produce a different result. It depends on the implementation of the function, but assuming its result relies only on the properties of each poll, then you could watch the poll and call the expensive function whenever it is changed:

.poll
...
{{expensivelyComputedValue}}

.directive('poll', function($rootScope, $modal) {
    return {
        ...
        link: function(scope, elem, attrs) {
            function someExpensiveComputation(id) { ... }

            scope.expensivelyComputedValue = someExpensiveComputation(scope.poll.id);
            scope.$watch('poll', function (newValue, oldValue) {
                if (newValue === oldValue) { return; }
                scope.expensivelyComputedValue = someExpensiveComputation(scope.poll.id);
            }, true);
        }
    }
});

Of course, if the result of the expensive computation depends only on a specific property of poll (and not the entire object), it suffices to watch this property only, thus keeping your watch-expression even more "light-weight". E.g.:

scope.$watch('poll.closed', function (...) {...});
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top