我有一个angular2组件'my-tree',我在我的父'my-app'组件中使用它。 'my-app'如下:
@Component({
selector: 'my-app',
providers: [],
template: `
<my-tree *ngFor="#node of nodes" [title]="node">
<my-tree *ngFor="#subNode of getSubNodes(node)" [title]="subNode">
</my-tree>
</my-tree>
`,
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: `
<ul>
<li><span>{{title}}</span></li>
<ng-content></ng-content>
</ul>
`,
directives: []
})
export class MyTree {
private title: string;
}
执行此操作时,将记录控制台,并显示以下错误 - 检查后,表达式'app2:15中的getSubNodes(节点)已更改。上一个值:'2.0.0,1.4.2'。当前价值:'2.0.0,1.4.2'。
有关实际代码,请参阅此plunk。
我的代码中的想法是创建一个树(只是一个例子),第一个级别来自一个数组(硬编码值),第二个级别来自一个函数,它返回给定当前节点的下一个集合(或价值)来自第一级。 并且它调用了这个函数,其中angular抱怨表达式被检查后被更改。虽然报告的值与错误消息中较早的值完全相同。 我在SO上搜索了这个错误,发现很少有引用,但大多数时候他们建议调用更改检测。我无法理解为什么这是必需的以及如何做到这一点。我还读到这只是一条诊断消息,它不会在生产模式中抛出。
是否无法在* ngFor内调用函数?应该怎么做才能摆脱这个错误?
答案 0 :(得分:3)
问题是
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'];
}
}
这里每次Angular检查它获取一个新数组实例的值,因此它们永远不会相同。 Angular不会仅仅比较数组的实例相等值。
此检查也仅在开发模式下完成。 另请参阅What is difference between production and development mode in Angular2?
这样就可以满足Angular
angular2 = ['2.0.0', '1.4.2'];
typeScript = ['1.7.3'];
js = ['es-6'];
getSubNodes( node: string ) {
if( node === 'Angular2') {
return this.angular2;
}
if ( node === 'typescript' ) {
return this.typeScript;
}
if ( node === 'js' ) {
return this.js;
}
}
答案 1 :(得分:1)
问题是getSubNodes(node)
违反了idempontent规则,因为每次调用该方法时都会返回一个新数组。
来自模板语法开发指南的Template Expressions section:
模板表达式可以创建或中断应用程序。请遵循这些指南,除非您有充分的理由在您完全理解的特定情况下打破它们。
....幂等表达式
在Angular术语中,幂等表达式总是返回完全相同的东西,直到其中一个相关值发生变化。
在JavaScript虚拟机的一次转弯中,相关值不应更改。如果幂等表达式返回字符串或数字,则在连续两次调用时返回相同的字符串或数字。 如果表达式返回一个对象(包括Date或Array),则在连续两次调用时返回相同的对象引用。
在开发模式下,如果违反幂等要求,Angular会抱怨,因为在开发模式下,模板绑定会被检查两次,以查找这些类型的违规。 Angular试图提供帮助,因为如果您正在做一些不同的事情,比如修改父组件中可见的应用程序状态,那么由于在更改检测期间单次通过组件树,该父组件的视图将不会更新。即,一旦检查了父组件的更改,即使后代组件更改了父组件在其视图/模板中绑定的某些数据,也不会再次检查它。
要解决此问题,请将代码重新修改为不违反规则。