当前位置: 首页 > 知识库问答 >
问题:

Angular 2 绑定到计算的 getter 给出了调试错误

暨修洁
2023-03-14

我正在与Angular 2和lodash合作。

我有一个关系模型,我有一个这样的获取器:

get relationsPerType() {
    return _(this.Relations)
        .groupBy(p => p.Type)
        .toPairs()
        .map(p => ({
            type: <MessageRelationType>p[0],
            relations: <Relation[]>p[1]
        }));
}

将relationsPerType的值绑定到*ngFor指令

编辑:这是我的绑定:

<div *ngFor="#relationGroup of Message.relationsPerType">
    ...
</div>

给我以下错误:

表达式 'Message.relationsPerType in MessagesDetailsComponent@60:8' 在检查后已更改。以前

这看起来是完全正确的,因为每次调用它时都要进行计算。

无论如何,在“计算”了这样的变量之后,我无法想象Angular 2变化检测如何检测到关系PerType实际发生了变化。比如将getter标记为不可变??

我想更好的方法是:

a) 从一开始就将计算出的 getter 值存储在属性中

b)使父对象不可变,以便Angular不跟踪属性的变化

有更好的方法吗?

共有2个答案

卢磊
2023-03-14

应改为缓存值并绑定到缓存的值,或者创建一个在数据更改时发出新事件的可观察量。

如果您绑定到{{的关系类型}},则每次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>
湛同
2023-03-14

经过一些挖掘,我发现了一个更好的使用装饰器的方法,比a)和b)提供的更好,因为:

a)我不想失去getter函数提供的“懒惰”计算并使一切成为属性

b) Immutable是一个可行的解决方案,但不适用于我的情况

因此,来自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}`

财产从这里。

 类似资料:
  • 我已经重新安装了node-sass,但这不起作用。

  • 因此,我在这里询问绑定表的概念。通常,只需对所有行/列使用ngFor即可。 然而,我想做的是,对于每个单元格,它应该绑定到一个具有两个属性的对象: <李>细胞内容李< / ><李>坳的头 在我的表中,我应该能够根据需要添加行或列。这很简单,但所有共享column_header的单元格都是棘手的部分。 现在这个表代表一个表单,所以我可以在用户单击submit后进行处理并解决问题。 我只是寻找其他聪明

  • 我的vue js网站上的数据正在渲染,但控制台中出现了一个未定义的错误。我正在应用程序中进行axios呼叫。vue从我的cms获取数据: 一个pp.vue } 然后在我的一个组件中,我调用getter来检索存储在vuex中的数据: 关于vue 然后在我的模板代码中引用: 一切都呈现良好,但这是我在web控制台中看到的错误: 我认为这个问题与我的组件的创建顺序有关。我正在将所有子组件导入应用程序。v

  • 怎么回事?为什么这不起作用? 环境 Visual Studio 2015更新1 ASP.NET 5和MVC6 DNX 4.5.1和5.0 Angular2打字稿

  • @CategoryValidator由CategoryValidatorImpl验证: 和CategoryController的一部分: 在输入字段中,当我输入一个空白时,验证器使用控制器中的hasErrors正确地发现它,但当我在发现空白并返回false后返回表单时,它会给出以下信息: