最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why does AngularJS filter only run once? - Stack Overflow

programmeradmin3浏览0评论

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=".6.2/angular.min.js"></script>
<div ng-app="app" ng-controller="TestController">
    <p>{{getText()}}</p>
    <p>{{'' | text}}</p>
</div>

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./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?

Share Improve this question edited Jul 15, 2017 at 5:12 Vivz 6,6302 gold badges18 silver badges34 bronze badges asked Mar 10, 2017 at 15:58 Omar MekyOmar Meky 6061 gold badge6 silver badges17 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 5

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.

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./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>

When an expression is used in a template, then AngularJS first evaluates the material/text inside braces (Interpolation) and then converts the value/output to string and then insert this string value into the HTML element/attribute.

From AngularJS Docs:- 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.

There are two exceptions to this rule:

  • In general, this applies only to filters that take primitive values as inputs. Filters that receive Objects as input are executed on each $digest, as it would be too costly to track if the inputs have changed.
  • Filters that are marked as $stateful are also executed on each $digest. See Stateful filters for more information. Note that no AngularJS core filters are $stateful.

As per documentation,

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.

There are two exceptions to this rule:

In general, this applies only to filters that take primitive values as inputs. Filters that receive Objects as input are executed on each $digest, as it would be too costly to track if the inputs have changed.

Filters that are marked as $stateful are also executed on each $digest. See Stateful filters for more information. Note that no AngularJS core filters are $stateful.

Since you have a primitive value which doesn't change, the filter doesn't have to execute again. Change the empty string '' to an object literal {} and see what happens ;)

Both bindings are being checked twice, but you can only see one being checked twice. In the case of the filter, the input is ''. Angular is only checking the INPUT (source) to the filter when dirty checking and it checks it twice and pares results. So it doesn't call the filter twice.

For the curly brace binding, the RESULT of the expression is checked twice, and so you can see your function being called twice.

But if you make the input to the filter a function like this you'll see it's called twice just like your curly brace binding and the filter is still called only once.

Changing the filter input to a function shows that input is checked twice and filter is called just once:

{{getText() | text}}
发布评论

评论列表(0)

  1. 暂无评论