Angular2: 嵌套的 *ngFor 导致了 'Expression has changed after it was checked' 错误。

11 浏览
0 Comments

Angular2: 嵌套的 *ngFor 导致了 'Expression has changed after it was checked' 错误。

我有一个Angular2组件'my-tree',我在父组件'my-app'中使用它。

'my-app'的代码如下:

@Component({

selector: 'my-app',

providers: [],

template: `

`,

directives: [MyTree]

})

export class App {

constructor() {

this.nodes = ['Angular2', 'typescript', 'js']

}

getSubNodes( node: string ) {

if( node === 'Angular2') {

return ['2.0.0', '1.4.2']

}

if ( node === 'typescript' ) {

return ['1.7.3'];

}

if ( node === 'js' ) {

return ['es-6'];

}

}

}

'my-tree'是一个简单的组件 -

@Component({
  selector: 'my-tree',
  providers: [],
  inputs: ['title'],
  template: `
    
  • {{title}}
`, directives: [] }) export class MyTree { private title: string; }

当执行这段代码时,控制台会记录以下错误 -

Expression 'getSubNodes(node) in App@2:15' has changed after it was checked. Previous value: '2.0.0,1.4.2'. Current value: '2.0.0,1.4.2'.

请参阅plunk以查看实际代码。

我的代码的思路是创建一棵树(仅为示例),第一层来自一个数组(硬编码的值),第二层来自一个函数,该函数根据第一层的当前节点(或值)返回下一组值。

而正是在调用这个函数的地方,Angular会抱怨表达式在检查后被改变了。尽管值在错误消息中报告的确实与之前完全相同。

我在SO上搜索了这个错误,并找到了一些参考资料,但大多数都建议调用变更检测。我无法理解为什么需要这样做,以及如何做。我还看到说这只是一个诊断消息,在生产模式下不会抛出。

在*ngFor中调用函数是不可能的吗?如何摆脱这个错误?

0
0 Comments

Angular2中嵌套*ngFor引发'Expression has changed after it was checked'问题的原因是每次Angular检查值时都会得到一个新的数组实例,因此它们永远不会相同。Angular只比较数组的实例相等性,而不比较值的相等性。这个检查只在开发模式下进行。

解决这个问题的方法是返回一个固定的数组实例,而不是每次都返回一个新的数组。可以将这些数组实例定义为类的属性,然后在函数中返回这些属性。

如果无法始终定义满足此条件的返回值,可以选择使用({changeDetection:ChangeDetectionStrategy.OnPush})并通知Angular进行更改。可以查看github.com/angular/angular/issues/4746或实现doCheck angular.io/docs/js/latest/api/core/DoCheck-interface.html。

总结起来,解决这个问题的方法有两种:一种是返回固定的数组实例,另一种是使用changeDetection或doCheck来通知Angular进行更改。

0
0 Comments

问题的原因是getSubNodes(node)违反了幂等规则,因为每次调用该方法时都会返回一个新的数组。

Angular的模板表达式部分的开发指南中提到:

模板表达式可以使应用程序变得成功或失败。除非您有非常充分的理由在特定情况下打破这些规则,否则请遵循以下准则。

...

幂等表达式

在Angular术语中,幂等表达式在其依赖值发生变化之前总是返回完全相同的内容。

在JavaScript虚拟机的单个执行过程中,依赖值不应该发生变化。如果幂等表达式返回一个字符串或数字,那么当连续两次调用时,它将返回相同的字符串或数字。如果表达式返回一个对象(包括Date或Array),那么当连续两次调用时,它将返回相同的对象引用。

在开发模式下,如果违反了幂等性要求,Angular会发出警告,因为在开发模式下,模板绑定会进行两次检查,以找出这些类型的违规行为。Angular试图提供帮助,因为如果您正在做一些不同的事情,比如修改在父组件中可见的应用程序状态,那么由于在更改检测期间只对组件树进行一次遍历,所以父组件的视图将不会更新。也就是说,一旦检查了父组件的更改,即使后代组件更改了父组件在视图/模板中绑定的一些数据,父组件也不会再次被检查。

为了解决这个问题,需要重新设计代码,以遵循这个规则。

0