非幂等过滤器导致无限$摘要错误

时间:2014-05-29 17:19:07

标签: angularjs angularjs-filter

试图了解角度滤镜的本质。所以我有这个:

<p>RandomCase: {{ aString | randomCase }}</p>

和此:

.filter 'randomCase', () ->
    (input) ->
        input.replace /./g, (c) ->
            if Math.random() > 0.5 then c.toUpperCase() else c

Coffeescript在这里制作了一个更干净的代码,在JSFiddle中找到了JS版本以及完整的例子:

http://jsfiddle.net/nmakarov/5LdKV/

重点是通过随机字母大写来装饰字符串。

它有效,但抛出了#$ 10 $ digest()迭代。中止&#34!;大多数时候。我认为由于某种原因,Angular会重新运行过滤器至少两次以查看输出是否相同。如果没有,将再次运行直到最后两场比赛。实际上,由于过滤器的代码产生随机字符串,因此它不太可能连续两次重复。

现在提出一个问题:是否有可能告诉Angular不要多次重新运行此过滤器?我不需要在代码中观察此过滤输出的值,因此不需要Angular来观察更改 - 即使是硬编码的&#34;字符串&#34;用来代替aString变量,代码行为相同 - 达到了10次迭代......

而且我知道我可以将randomizing逻辑放在一个控制器中并将结果绑定到$ scope.aString并且它可以正常工作 - 我试图理解Angular的过滤方式。

干杯。

2 个答案:

答案 0 :(得分:2)

在没有黑客攻击的情况下,无法在监视的表达式中使用非幂等过滤器。这是我能想到的最简单的一个,它会使滤波器具有幂等性......

使用memoizing函数确保后续调用传递相同参数的过滤器返回相同的结果。

使用下划线的示例:

myApp.filter('randomCase', function() {
    return _.memoize(function (input) {
        console.log("random");
        return input.replace(/./g, function(c) {
            if (Math.random() > 0.5) {
                return c.toUpperCase();
            } else {
                return c;
            }
        });
    });
});

Updated Fiddle

答案 1 :(得分:1)

过滤器本身仅在评估带有|运算符(例如someVar | someFilter)的表达式时运行。 Anuglar's dirty checking导致表达式被多次评估。

简而言之,Angular一遍又一遍地运行表达式aString | randomCase,直到它没有改变。那时它知道要放入DOM的内容。为了防止在该值不停止更改时无限循环,它会抛出无限$ digest错误。

因此,过滤器始终至少运行两次。一旦获得初始值,然后第二次将其与第一个值进行比较。

通过将随机化逻辑放在控制器中,您可以在HTML中使用{{randomizedString}}randomizedString的值不会从第一次评估时发生变化,因此可以在不遇到无限$ digest错误的情况下实现最终目标。