Claudiu Claudiu - 1 year ago 77
AngularJS Question

Angular2 method binding error: "value has changed after it was checked"

I am trying to make a circle board in Angular2. For the example I want to make 10 circles but in reality this number can change. I want to calculate the radius of each circle, so it would be dynamic and not static. See the picture for exampleenter image description here

This is my code

template: `
<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>

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;

But I get the following error:

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]

Is there maybe a better way of writing this for loop with
instead of writing this in a separate method?

Answer Source

In development mode (the default), change detection is run twice to ensure that model changes have stabilized. This means that the ngFor loop is evaluated twice. Hence property x will continue to be decremented the second time change detection runs. Other activity in your app will also cause change detection to run, and x will continue to be decremented. Therefore, you must write all view functions, like calculateRadius(), assuming they will be executed many times. E.g.:

public calculateRadius(i):number{
    return this.x - i*this.distanceBetweenCircles;

The Template Syntax dev guide mentions this when it describes idempotent expressions.

This will also solve the value has changed after it was checked problem.

You also need to bind SVG attribute r using this syntax: [attr.r]="...", not [style.r]="...".