Angular 2 绑定到计算的 getter 会导致调试错误
Posted
技术标签:
【中文标题】Angular 2 绑定到计算的 getter 会导致调试错误【英文标题】:Angular 2 bind to computed getter gives debug erros 【发布时间】:2016-08-12 17:21:26 【问题描述】:我正在使用 Angular 2 和 lodash。
我有一个带关系的模型,我有一个像这样的吸气剂:
get relationsPerType()
return _(this.Relations)
.groupBy(p => p.Type)
.toPairs()
.map(p => (
type: <MessageRelationType>p[0],
relations: <Relation[]>p[1]
));
将relationshipPerType 的值绑定到*ngFor 指令
编辑:这是我的绑定:
<div *ngFor="#relationGroup of Message.relationsPerType">
...
</div>
给我以下错误:
表达式“MessagesDetailsComponent@60:8 中的 Message.relationsPerType” 检查后有变化。上一页
这似乎是完全正确的,因为确实每次调用它时都会计算它。
无论如何,拥有像这样的“计算”变量,我无法想象 Angular 2 更改检测如何检测到 RelationsPerType 实际发生了变化。 比如将 getter 标记为不可变?
我想更好的方法是:
a) 从一开始就将计算得到的 getter 值存储在属性中
b) 使父对象不可变,以便 Angular 不跟踪属性的更改
有没有更好的方法来做到这一点?
【问题讨论】:
【参考方案1】:您应该缓存该值并绑定到缓存的值,或者创建一个可在数据更改时发出新事件的 observable。
如果您绑定到relationsPerType
,则每次 Angular 检查是否发生更改时都会创建一个新集合,并且 Angular 会将此视为更改,因为它会获取两个不同的实例,即使它们可能包含相同的数据。
calcRelationsPerType()
this relationsPerType = _(this.Relations)
.groupBy(p => p.Type)
.toPairs()
.map(p => (
type: <MessageRelationType>p[0],
relations: <Relation[]>p[1]
));
然后像这样的绑定应该可以正常工作:
<div *ngFor="#relationGroup of Message.relationsPerType">
...
</div>
【讨论】:
嘿,君特!我认为您的第一个 sn-p 中有一个错字:this relationsPerType = return _(this.Relations)
;-)
感谢君特。您所说的实际上是“a)从一开始就将计算得到的 getter 值存储在属性中”,在数据绑定之前调用 calcRelationsPerType() 需要付出更多努力。
很难判断您在问题中提供的信息是否付出了很多努力。您需要找到一种方法来在结果取决于值更改时重新计算它。恕我直言,最容易理解的解决方案是我在回答中显示的内容。更高级的是使用 observables。您的装饰器方法也很有趣,但我认为使缓存无效与调用重新计算非常相似。
君特,你说得对,让缓存失效。 Observables 也是一个不错的选择。【参考方案2】:
经过一番挖掘,我发现使用 decorators 的方法比 a) 和 b) 提供的更好,因为:
a) 我不想放弃 getter 函数提供的“惰性”计算并将所有内容都变成属性
b) 不可变是一种可行的解决方案,但不适用于我的情况
因此,来自 C# 和大量面向方面的编程(参见 PostSharp),我终于设法创建了一个缓存属性 getter 装饰器 函数,每个对象只评估一次:
function cachedProperty(target: any, key: string, descriptor: PropertyDescriptor)
let originalGetter = descriptor.get;
descriptor.get = function ()
let cachSetted = this[`__cachedsetted$key`];
if (typeof cachSetted !== 'undefined')
return this[`__cached$key`];
this[`__cachedsetted$key`] = true;
return this[`__cached$key`] = originalGetter.call(this);
之后所有需要改变的就是用@cachedProperty 装饰器装饰getter,如下所示:
@cachedProperty
get relationsPerType()
return _(this.Relations)
.groupBy(p => p.Type)
.toPairs()
.map(p => (
type: <MessageRelationType>p[0],
relations: <Relation[]>p[1]
)).value();
使用此装饰器,对象只会更改一次,因此 Angular 2 依赖注入不会抱怨。此外,我不会放弃“惰性”评估,也不会添加更改架构的辅助属性。
如果缓存变得陈旧,当然必须处理他想要使缓存失效的情况。这将需要删除
`__cachedsetted$key`
来自此的属性。
【讨论】:
以上是关于Angular 2 绑定到计算的 getter 会导致调试错误的主要内容,如果未能解决你的问题,请参考以下文章