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
If I click the button instead of pressing enter on keyboard
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).
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() {
}
}
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With