Angular 2 Modal Popup Error “Expression has changed after it was checked”

╄→尐↘猪︶ㄣ 提交于 2019-12-07 05:39:58

问题


Youtube video demonstrating the problem

Github repository for the demo app

I have a very simple app with an app component, a child component (account), alert service that handles a message dialog component (popup modal).

For demonstrating purpose, I have two identical forms, one inside app.component.ts and one inside account.component.ts. Each of them has a button that calls the alert service to show the message dialog modal.

The problem is that when I click in the input field of the form for the child component (account.component.ts) and "press enter on my keyboard", I get this error

EXCEPTION: Error in ./AccountComponent class AccountComponent - inline template:2:2 caused by: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'. Note that this error dose not occur at any other situation mentioned below

  1. If I click the button instead of pressing enter on keyboard

  2. The form from app.componen.ts does not seem to have any issue even when I press enter. It seems to be just the child component (accouunt.component.ts).

  3. If I click the input for account.component, enter something, click the button, no error shown, delete the input, press enter, no error shown now comparing to before

I have look into SO and google and it seems like people are having the same issue and resolving it by calling change detect. However, I have tried that and put it in places such as just after modal is shown and it didn't work. Also, if that would solve it, then it doesn't explain why the form in app.component.ts does not cause me this error.

Below are some code snippets, the full demo project can be found on the github link above. This problem has be troubling me for days. Much appreciated for the help.

app.component.html

<label>This form is from app.component.html</label>
<form name="form" [formGroup]="changePasswordForm" (ngSubmit)="onUpdatePassword()">
    <input placeholder="Old Password" formControlName="oldPassword">
    <button class="btn btn-success">Update Password</button>
</form>

<br><br><br><br>

<label>This form is from account.component.html</label>
<router-outlet> </router-outlet>

<template ngbModalContainer></template>

app.component.ts

export class AppComponent implements OnInit {

    private changePasswordForm: FormGroup;

    constructor(
      private formBuilder: FormBuilder,
      private alertService: AlertService,
    ) { }

    ngOnInit() {
      this.changePasswordForm = this.formBuilder.group({
        oldPassword: [''],
      })
    }

    onUpdatePassword() {
      this.alertService.alertPopup('test2', 'asfafa')
    }
}

account.component.html

<form name="form" [formGroup]="changePasswordForm" (ngSubmit)="onUpdatePassword()">
  <input placeholder="Old Password" formControlName="oldPassword">
  <button class="btn btn-success">Update Password</button>
</form>

account.component.ts

export class AccountComponent implements OnInit {

  private changePasswordForm: FormGroup;

  constructor(
    private formBuilder: FormBuilder,
    private alertService: AlertService,
  ) { }

  ngOnInit() {
    this.changePasswordForm = this.formBuilder.group({
      oldPassword: [''],
    })
  }

  onUpdatePassword() {
    this.alertService.alertPopup('test2', 'asfafa')
  }
}

alert.service.ts

@Injectable()
export class AlertService {
    private subject = new Subject<any>();
    private keepAfterNavigationChange = false;

    constructor(
        private router: Router,
        private modalService: NgbModal,
    ) { }


    alertPopup(title: string, content: string) {
        // open modal to check if worked over night
        const modalRef = this.modalService.open(MessageDialogComponent);

        modalRef.componentInstance.titleText = title
        modalRef.componentInstance.bodyText = content

        modalRef.result
            .then(response => {
            })
            .catch(() => {
                return
            })
    }
}

message-dialog.component.html

<div class="modal-header">
  <h4 class="modal-title">{{titleText}}</h4>
</div>

<div class="modal-body">
  <p>{{bodyText}}</p>
</div>

message-dialog.component.ts

export class MessageDialogComponent implements OnInit {

  @Input() titleText: string;
  @Input() bodyText: string;

  constructor(
    public activeModal: NgbActiveModal,
  ) { }

  ngOnInit() {
  }

}


回答1:


Seems your error occurs after execution following code:

ngAfterViewInit() {
    if (!this._elRef.nativeElement.contains(document.activeElement)) {
      this._renderer.invokeElementMethod(this._elRef.nativeElement, 'focus', []);
    }
}

https://github.com/ng-bootstrap/ng-bootstrap/blob/1.0.0-alpha.20/src/modal/modal-window.ts#L65

on input is fired blur event that marks your control as touched.

It doesn't work for AccountComponent because detection changes in AccountComponent occurs before ngbModalContainer while FormGroup within app.component.html gets right values.

Possible solutions:

1) mark your controls as touched before opening modal

account.component.ts

onUpdatePassword() {
  Object.keys(this.changePasswordForm.controls).forEach(key => {
     this.changePasswordForm.controls[key].markAsTouched();
  });

  this.alertService.alertPopup('test2', 'asfafa')
}

2) change order tags

app.component.html

<template ngbModalContainer></template>
<router-outlet> </router-outlet>



回答2:


I even gone through same error once,

Use ngAfterViewInit() in your appComponent instead ngOnInit.

If that didn't solve just try

setTimeOut(function(){
//Your Code
},1)


来源:https://stackoverflow.com/questions/42323418/angular-2-modal-popup-error-expression-has-changed-after-it-was-checked

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!