Javascript Angular 2绑定到计算getter会导致调试错误
我正在与Angular 2和lodash合作 我有一个有关系的模型,我有一个这样的getter:Javascript Angular 2绑定到计算getter会导致调试错误,javascript,typescript,angular,decorator,lodash,Javascript,Typescript,Angular,Decorator,Lodash,我正在与Angular 2和lodash合作 我有一个有关系的模型,我有一个这样的getter: get relationsPerType() { return _(this.Relations) .groupBy(p => p.Type) .toPairs() .map(p => ({ type: <MessageRelationType>p[0], relation
get relationsPerType() {
return _(this.Relations)
.groupBy(p => p.Type)
.toPairs()
.map(p => ({
type: <MessageRelationType>p[0],
relations: <Relation[]>p[1]
}));
}
get relationsPerType(){
return(this.Relations)
.groupBy(p=>p.Type)
.toPairs()
.map(p=>({
类型:p[0],
关系:p[1]
}));
}
将relationsPerType的值绑定到*ngFor指令
编辑:这是我的绑定:
...
给我以下错误:
表达式“Message.relationsPerType in”MessagesDetailsComponent@60:8'
已在检查后更改。先前的
这似乎是完全正确的,因为每次调用它时,都会计算它
在任何情况下,有了这样的“计算”变量,我无法想象Angular 2 change detection如何检测到relationsPerType实际发生了变化。
类似于将getter标记为不可变
我想更好的办法是:
a) 从一开始将计算出的getter值存储在属性权限内
b) 使父对象不可变,以便Angular不跟踪特性的更改
有更好的方法吗 您应该缓存该值并绑定到缓存的值,或者创建一个在数据更改时发出新事件的可观察对象 如果绑定到
{{relationsPerType}}
则每次Angular检查是否发生更改时都会创建一个新集合,Angular将此视为更改,因为它会获得两个不同的实例,即使它们可能包含相同的数据
calcRelationsPerType() {
this relationsPerType = _(this.Relations)
.groupBy(p => p.Type)
.toPairs()
.map(p => ({
type: <MessageRelationType>p[0],
relations: <Relation[]>p[1]
}));
}
calcreationspertype(){
this relationsPerType=389;(this.Relations)
.groupBy(p=>p.Type)
.toPairs()
.map(p=>({
类型:p[0],
关系:p[1]
}));
}
那么像这样的绑定应该可以很好地工作:
<div *ngFor="#relationGroup of Message.relationsPerType">
...
</div>
...
经过一番挖掘,我发现使用装饰器比a)和b)提供的更好,如下所示:
a) 我不想失去getter函数提供的“懒惰”计算,让一切都成为属性
b) Immutable是一个可行的解决方案,但不适用于我的情况
因此,通过C#和大量面向方面的编程(参见PostSharp),我最终创建了一个缓存属性getter decorator函数,每个对象只计算一次:
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();
}
来自此的属性。嘿,甘特!我认为您的第一个代码片段中有一个输入错误:
this relationsPerType=return(this.Relations)
;-)谢谢你,甘特。您所说的实际上是“a)从一开始就将计算出的getter值存储在一个属性right中”,在数据绑定之前调用calcRelationsPerType()需要做很多额外的工作。很难说您在问题中提供的信息是否需要做很多工作。当结果所依赖的值发生变化时,您需要找到一种方法使其重新计算。最容易理解的解决方案是我在回答中所显示的内容。更先进的方法将是使用可观测数据。您的decorator方法也很有趣,但我认为使缓存无效与调用重新计算非常类似。Günter,关于使缓存无效,您是对的。在那里,可观测也是一个不错的选择。
@cachedProperty
get relationsPerType() {
return _(this.Relations)
.groupBy(p => p.Type)
.toPairs()
.map(p => ({
type: <MessageRelationType>p[0],
relations: <Relation[]>p[1]
})).value();
}
`__cachedsetted${key}`