Angular2方法绑定错误:"值在检查后发生了更改"。

4
我将尝试在Angular2中制作一个圆形板。例如,我想制作10个圆形,但实际上这个数字可能会改变。我想计算每个圆的半径,使其具有动态性而不是静态性。请参见以下图片示例:enter image description here 以下是我的代码:
@Component({
    selector:"circle"
    template: `
  <svg>
    <circle *ngFor='#item of forLength #i=index #l=last #e=even'
            cx="50%" cy="50%" [style.r]="calculateRadius()" stroke="black" stroke-width="5" fill="white"></circle>
  <svg/>  
    `
})

export class CircleComponent{
    public maxRadius:number=25;
    public totalRounds:number=10;
    public x:number=30;

    public calculateRadius():number{
        var distanceBetweenCircles=this.maxRadius/(this.totalRounds-1);
        this.x-= distanceBetweenCircles;
        return this.x;
    }
}

但我遇到了以下错误:
calculateRadius() in CircleComponent@7:30' has changed after it was checked. 
    Previous value: '-7.500000000000007'. 
    Current value: '-36.66666666666668' in [calculateRadius() in CircleComponent@7:30]

*ngFor改写这个for循环有更好的方法吗?而不是写在一个单独的方法中。


你在模板中调用了calculateRadius()函数吗?你在模板中设置SVG的r属性吗? - Mark Rajcok
@MarkRajcok 抱歉,我在代码中写错了,现在已经更新了代码。我在<circle>标签中使用calculateRadius()函数。 - Claudiu Matei
2个回答

15
在开发模式下(默认情况下),更改检测会运行两次以确保模型更改已经稳定。这意味着ngFor循环将被评估两次。因此,属性x将在第二次更改检测运行时继续递减。应用程序中的其他活动也会导致更改检测运行,x将继续递减。因此,您必须编写所有视图函数,例如calculateRadius(),假设它们将被执行多次。例如:
public calculateRadius(i):number{
    return this.x - i*this.distanceBetweenCircles;
}

模板语法开发指南在描述幂等表达式(idempotent expressions)时提到了这一点。
这也将解决“在检查后值已更改”问题(value has changed after it was checked problem)。
您还需要使用以下语法绑定SVG属性r[attr.r]="...",而不是[style.r]="..."Plunker

谢谢!没有比这更好的解释了。现在它可以工作了! - Claudiu Matei
1
自从Angular2 RC3以来,您可以通过更改变更检测策略来解决此问题:import {ChangeDetectionStrategy} from '@angular/core'; @Component({changeDetection: ChangeDetectionStrategy.OnPush}) - Becario Senior
1
@BecarioSenior,我不建议使用OnPush作为解决此问题的方案。 OnPush应该与仅依赖其输入属性且此处没有输入属性的组件一起使用。即使我们要添加一个输入属性,组件方法也不应以这种方式修改输入属性的值(在这种情况下,我认为这样的输入属性应该是只读的)。此外,在模板中使用的表达式应该是幂等的。 - Mark Rajcok

0
“value has changed after it was checked”
任何“值”的返回必须是确定性的。这意味着,如果我使用相同的输入调用“值”(可能是“calculateRadius()”),它应该给出相同的输出。
所以把“index”传入“calculateRadius”(或者任何导致错误的“值”函数)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接