【问题标题】:AngularDart custom filter call() method required to be idempotent?AngularDart自定义过滤器调用()方法需要幂等吗?
【发布时间】:2014-02-14 20:59:10
【问题描述】:

Angular Dart 教程的主要运行示例是一个Recipe Book 应用程序Chapter 5 on filters and services 末尾的练习建议尝试“创建一个 [自定义] 过滤器,将配方中 [列出的每种成分] 的所有数量相乘”,从而允许“用户可以将食谱翻倍、三倍或四倍。”例如。 “1/2杯面粉”的成分加倍后会变成“1杯面粉”。

我编写了这样一个自定义过滤器:它需要一个Ingredients 列表(由一个quantity 和一个description 组成)并返回一个新的Ingredients 列表(数量增加),但我收到以下错误:

5 $digest() iterations reached. Aborting!

我的问题是:AngularDart 自定义过滤器call() 方法的要求和/或允许的行为是什么?例如,显然允许从其输入列表中删除(即过滤)元素,但它也可以添加新元素或替换元素吗? Dart angular.core NgFilter 文档简单地说“过滤器是一个带有调用方法的类”。我没有找到更多细节。

this AngularJS post 的答案推断,似乎重复调用call() 应该(最终?)产生“相同的结果”。如果是这样,这将是一个合理的约束。

产生“相同的结果”可能意味着call() 需要幂等,但在 Dart 的情况下,这种幂等性应该相对于==(对象等价)而不是identical() (对象身份),恕我直言。我使用以下小示例进行了一些测试来说明问题:

  • main.dart
    import 'package:angular/angular.dart';

    class A { }

    @NgFilter(name:'myFilter') class MutatingCustomFilter {
      final A _a = new A();
      call(List list) => new List.from(list)..add(_a); // runs ok.
      // call(List list) => new List.from(list)..add(new A()); // gives error
    }

    class MyAppModule extends Module {
      MyAppModule() { type(MutatingCustomFilter); }
    }

    main() => ngBootstrap(module: new MyAppModule());
  • index.html 摘录
    <ul>
      <li ng-repeat="x in [1,2,3] | myFilter">{{x}}</li>
    </ul>

如果我将class A 的正文更改为

@override bool operator==(other) => true;
@override int get hashCode => 1;

这使得A 的所有实例都被视为==,然后main.dart 中call() 的第二个实现(带有add(new A()) 的那个)仍然给出错误(尽管是不同的)。

我可以看到如何在不使用自定义过滤器的情况下解决教程练习,但我试图不放弃寻找可以按要求工作的过滤器的挑战。我是 Angular 的新手,并决定加入 AngularDart,因此在解释 call() 的各种风格的效果或查找 call() 的预期行为的文档方面有任何帮助,(或者让我知道你是否认为这样的自定义过滤器根本无法编写!)将不胜感激。

【问题讨论】:

    标签: filter dart semantics angular-dart idempotent


    【解决方案1】:

    迭代次数过多

    当 Angular 检测到模型发生变化时,它会执行一个反应函数。反应函数可以进一步改变模型。这将使模型处于不一致的状态。出于这个原因,我们重新运行更改检测,这可以进一步创建更多更改。出于这个原因,我们不断重新运行更改,直到模型稳定。但是在放弃之前我们应该重新运行多少次变更检测呢?默认为 5 次。如果模型在 5 次迭代后不稳定,我们就放弃。这就是你的情况。

    变化检测

    对象什么时候改变了?可以使用identical==(等于)。可以为每个参数提出好的论据,但我们选择使用identical,因为它快速且一致。使用==(等于)很棘手,它会对更改检测算法产生负面影响。

    过滤器和数组

    当一个过滤器操作一个数组时,执行它别无选择,只能创建一个新的数组实例。这打破了相同的,但幸运的是它被输入ng-repeat,它使用自己的算法进行数组内容检测,而不是数组检测。虽然数组在运行之间不必相同,但其内容必须相同。否则ng-repeat 无法区分插入和更改,需要做适当的动画。

    您的代码

    您的过滤器的问题在于它会在摘要循环的每次迭代中创建新实例。这些新实例会阻止模型稳定并因此导致错误。 (有解决这个问题的计划,但我们需要几周才能到达那里。)

    解决方案

    您的解决方案正在尝试创建一个过滤器,该过滤器使用整个数组,然后尝试为ng-repeat 创建一个新数组。一个不同的(首选)解决方案是保留ng-repeat 迭代,而是将过滤器放在创建数量的绑定上并将其应用到那里。

    <span>{{recipe.qty | myFilter:multiply}}</span>
    

    【讨论】:

    • 感谢Misko的详细回复。我期待更多地了解“解决此问题的计划”。
    • 根据您的反馈,我收集到建议的解决方案只有在 myFilter 是幂等 w.r.t 时才有效。相同(或更准确地说,在 5 次迭代内收敛)。 nums 似乎就是这种情况。在成分的类型quantity 是一个特殊的数字类的实现中,比如Rational,支持像1 1/3 这样的数字的整数处理(比如在“1 1/3 杯面粉”中,然后是这样的过滤器基于 -based 的解决方案仍然无法工作(模花式实习)。还是我错过了什么?
    • 在执行“解决此问题的计划”之前,我找到了一种解决方法:将成分值导入(自定义)toString 过滤器。
    猜你喜欢
    • 1970-01-01
    • 2011-06-20
    • 2011-10-20
    • 2013-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    相关资源
    最近更新 更多