Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does AngularJS filter only run once?

Consider the following example:

    angular.module('app', []).controller('TestController', function($scope) {
      $scope.getText = function() {
          console.log('getting text');
          return 'text';
      };
  }).filter('text', function() {
      return function() {
          console.log('text filter');
          return 'text';
      };
  });
 

  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
<div ng-app="app" ng-controller="TestController">
    <p>{{getText()}}</p>
    <p>{{'' | text}}</p>
</div>

Notice that the getText() function runs twice whereas the filter only runs once. I assume the getText() function runs twice to make sure the model is now stable. Why not the same behavior for the filter?

like image 735
Omar Meky Avatar asked Jan 05 '23 09:01

Omar Meky


2 Answers

The documentation is pretty clear on this subject:

In templates, filters are only executed when their inputs have changed. This is more performant than executing a filter on each $digest as is the case with expressions.

Here's the source.

like image 107
Cosmin Ababei Avatar answered Jan 06 '23 21:01

Cosmin Ababei


Cosmin is exactly right - and here's a demo to prove it (which, coincidentally, will cause a stack overflow at some point) - when getText() is called, it assigns a new value to the input of the text filter, which causes it to re-evaluate, which causes another digest cycle, which causes the filter to reevaluate... which eventually causes something like a stack overflow.


EDIT I removed a testing portion that was causing the overflow - this will only have the filter evaluate twice, since getText is called only twice.

angular.module('app', []).controller('TestController', function($scope) {
  $scope.foo = 'bar';
  $scope.getText = function() {
    console.log('getting text');
    $scope.foo += 'a';

    return 'text';
  };
}).filter('text', function() {
  return function() {
    console.log('text filter');
    return 'text';
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
<div ng-app="app" ng-controller="TestController">
  <p>{{getText()}}</p>
  <p>{{foo | text}}</p>
</div>
like image 22
Dan Field Avatar answered Jan 06 '23 23:01

Dan Field