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



试着理解Angular过滤器的本质。这里是:

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

:

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

Coffeescript使得这里的代码更干净,JS版本可以在JSFiddle中找到,以及完整的示例:

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

关键是通过将随机字母大写来修饰字符串。

可以工作,但是会抛出"达到10 $digest()迭代"。流产!"我想,出于某种原因,Angular至少会重新运行两次过滤器,以确保输出是相同的。如果没有,将再次运行它,直到最后两个匹配。实际上,由于过滤器的代码生成一个随机字符串,因此它不太可能在一行中重复两次。

现在问题来了:有没有可能告诉Angular不要重复运行这个过滤器超过一次?我不需要在代码中观察这个过滤输出的值,所以Angular不需要观察这些变化——即使用一个硬编码的"字符串"代替aString变量,代码的行为也是一样的——达到了10次迭代……

并且我知道我可以将randomizing逻辑放在控制器中并将结果绑定到$作用域。我正在尝试理解过滤器的Angular方式。

欢呼。

在监视表达式中使用非幂等过滤器是不可能的。这是我能想到的最简单的一个,它将使过滤器幂等…

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

使用下划线的例子:

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;
            }
        });
    });
});

更新小提琴

过滤器本身只会在计算带有|运算符(例如someVar | someFilter)的表达式时运行。正是angular的脏检查导致表达式被求值多次。

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

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

通过将随机化逻辑放入控制器中,您将在HTML中拥有类似{{randomizedString}}的内容。randomizedString的值在第一次求值后不会改变,因此可以实现您的最终目标,而不会遇到无限的$digest错误。

最新更新