4

When passing an object through multiple directives of childcomponents I get the following error message:

Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.

template:

<form *ngIf="deliveryrequest" [formGroup]="deliveryRequestForm" (ngSubmit)="onSubmit(deliveryRequestForm)">
    <h4>Detail: {{deliveryrequest.nr}}</h4>
    <div class="row">
        <div class="col-lg-6 col-xs-12 col-md-6 col-sm-6">
            <drr-request [request]="deliveryrequest" [group]="deliveryRequestForm"></drr-request>
            <drr-received [received]="deliveryrequest" [group]="deliveryRequestForm"></drr-received>
        </div>
        <div class="col-lg-6 col-xs-12 col-md-6 col-sm-6">
            <drr-requester [requester]="deliveryrequest" [group]="deliveryRequestForm"></drr-requester>
        </div>
    </div>

    <div class="row">
        <div class="col-lg-12 col-xs-12">
            <button type="submit" class="btn btn-primary" [disabled]="!deliveryRequestForm.valid">Bewaren</button>
        </div>
    </div>
</form>

requester component template:

<div [formGroup]="requesterForm">
    <div class="row">
        <div class="col-lg-12 col-xs-12 col-md-12 col-sm-12">
            <div class="panel panel-default">
                <div class="panel-heading">Aanvrager</div>
                <div class="control-group">
                    <drr-person [required]="true" (isMinorEmittor)="setPersonIsMinor($event)" [group]="requesterForm"></drr-person>
                </div>
            </div>
        </div>
    </div>
    <div class="row" formArrayName="responsiblePersonsNationalNumbers">
        <div class="col-lg-6 col-xs-12 col-md-6 col-sm-6"
             *ngFor="let responsible of requesterForm.controls.responsiblePersonsNationalNumbers.controls; let i=index; trackBy:i">
            <div class="panel panel-default">
                <div class="panel-heading">Verantwoordelijke {{i + 1}}</div>
                <div class="control-group" [formGroupName]="i">
                    <drr-person [required]="i === 0" [group]="requesterForm.controls.responsiblePersonsNationalNumbers.controls[i]"></drr-person>
                </div>
            </div>
        </div>
    </div>
</div>

person component template:

<p-growl [value]="msgs"></p-growl>
<div [formGroup]="personForm">
    <div class="row">
        <div class="col-lg-5">
            <label>Rijksregisternummer</label>
        </div>
        <div class="col-lg-7">

            <div [ngClass]="{ 'has-error': personForm.controls.nationalnumber.invalid, 'has-success': personForm.controls.nationalnumber.valid, 'has-feedback': true }">
                <input type="text" 
                       class="form-control"
                       data-mask="99.99.99-999.99"
                       placeholder="99.99.99-999.99"
                       (keyup)="lookupPerson($event)"
                       aria-describedby="inputSuccess2Status">
                <span class="glyphicon form-control-feedback" [ngClass]="{ 'glyphicon-ok' : personForm.controls.nationalnumber.valid, 'glyphicon-remove' : personForm.controls.nationalnumber.invalid }" aria-hidden="true"></span>
                <div id="inputSuccess2Status" class="sr-only">
                    <span *ngIf="personForm.controls.nationalnumber.valid">(success)</span>
                    <span *ngIf="personForm.controls.nationalnumber.invalid">(error)</span>
                </div>
            </div>
            <div *ngIf="personForm.controls.nationalnumber.dirty && !personForm.controls.nationalnumber.valid">
                <p *ngIf="personForm.controls.nationalnumber.errors" class="text-danger">
                    {{formErrors.nationalnumber}}
                </p>
            </div>
            <!--due to data-mask not passing value-->
            <input type="hidden" formControlName="nationalnumber" />
        </div>
    </div>
    <div *ngIf="person">
        <div class="row">
            <div class="col-lg-5">
                <label>Naam</label>
            </div>
            <div class="col-lg-7">{{person.familyName}}</div>
        </div>
        <div class="row">
            <div class="col-lg-5">
                <label>Voornaam</label>
            </div>
            <div class="col-lg-7">{{person.givenName}}</div>
        </div>
        <div class="row">
            <div class="col-lg-5">
                <label>Geboortedatum</label>
            </div>
            <div class="col-lg-7">{{person.birthDate | stringformat : 'xxxx-xx-xx' }}</div>
        </div>
        <div class="row">
            <div class="col-lg-5">
                <label>Adres</label>
            </div>
            <div class="col-lg-7" *ngIf="person.streetName">
                {{person.streetName}} {{person.houseNumber}} {{person.houseNumberExtension}}, {{person.postalCode}} {{person.municipalityName}}
            </div>
        </div>
        <div class="row" *ngIf="person.isMinor">
            <div class="col-lg-5">
                <label>Aanvraag minderjarige</label>
            </div>
            <div class="col-lg-7">
                <span>{{person.isMinor ? "Ja" : "Nee" }}</span>
            </div>
        </div>
    </div>
</div>
user2963570
  • 381
  • 6
  • 21

3 Answers3

6

If a bound value is changed during change detection this exception is thrown.

I assume it's caused by deliveryrequest.

For example a getter that returns different values when called subsequently.

get deliveryrequest() {
  return randomNumber = Math.random() >= 0.5;
}

A workaround (that wouldn't work for above example) but usually is a simple way to avoid the exception is to invoke change detection explicitely:

constructor(private changeDetectorRef:ChangeDetectorRef){}

ngOnChanges()  {
  this.deliveryrequest = randomNumber = Math.random() >= 0.5;
  this.changeDetectorRef.detectChanges();
}

If this is the right approach for you is hard to tell because your question doesn't provide enough information.

The best way is to avoid this exception but that's not always feasible.

This exception is also only thrown in development mode.
See also What is difference between production and development mode in Angular2?

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Thank you for your response. How can the value of deliveryrequest be changed when it gets its value oninit as a result of an api call? – user2963570 Dec 22 '16 at 13:08
  • I made several assumption because I can't know what is actually going on in your application. The error message doesn't explicitly say that `deliveryrequest` caused is. All it says that it's a field that changed from `true` to `false`. I just hoped that the information I provided helps you to with further investigation. It would help if you would add more code to your question. – Günter Zöchbauer Dec 22 '16 at 13:10
  • Okay. When I remove the drr-requester component. The error goes away so I assume it's going to be triggered somewhere there. I updated the post. – user2963570 Dec 22 '16 at 13:21
  • It could be caused by one of `[ngClass]="{ 'has-error': personForm.controls.nationalnumber.invalid,` try to change them to `[ngClass]="{ 'has-error': personForm.get('nationalnumber').invalid,`. It is a common cause but I don't remember what is the best way to avoid it. – Günter Zöchbauer Dec 22 '16 at 13:27
  • Sorry for the late answer but this doesn't solve the problem either – user2963570 Jan 12 '17 at 14:36
  • Sorry, then I don't know. – Günter Zöchbauer Jan 12 '17 at 14:39
  • In the requester component I do the following: [required]="true" For validation purposes I then check whether this field is required or not. Its on this snippet of code the error gets thrown. – user2963570 Jan 13 '17 at 09:14
  • ngOnInit I then check whether this property is true or false. Like so if (!this.required). Any idea? – user2963570 Jan 13 '17 at 09:18
  • I'm getting this same error when the ngSwich changes so it would be the same time that your *ngIf changes. did you ever figure out the issue? – JamTay317 Jan 16 '17 at 04:43
6

It is very strangely, because the solution is simple. I had this error in the same place. I read an interesting article about the error. But i solved this otherwise.
From

<div class="row">
    <div class="col-lg-12 col-xs-12">
        <button type="submit" class="btn btn-primary" [disabled]="!deliveryRequestForm.valid">Bewaren</button>
    </div>
</div>

To

<div class="row">
    <div class="col-lg-12 col-xs-12">
        <button type="submit" class="btn btn-primary" [attr.disabled]="!deliveryRequestForm.valid">Bewaren</button>
    </div>
</div>
Sergey Andreev
  • 1,398
  • 3
  • 16
  • 26
4

Try adding ChangeDetectionStrategy from angular core and also add in the Component.

import {  Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'page1',
  templateUrl: 'page1.html',
})
Biranchi
  • 16,120
  • 23
  • 124
  • 161