Reputation: 57852
I'm trying to migrate an app to using ChangeDetectionStrategy.OnPush
. However, I'm running into a bit of a blocker trying to work with some reactive forms.
I've got a reusable control that shows validation messages based on some of the state flags (e.g. *ngIf="control.touched && control.invalid"
). The problem I'm running into is that there's no way to detect when the touched
flag changes, and therefore no way to trigger change detection using ChangeDetectorRef
.
It could be done with a reference to the input element itself by listening for a click
event, but that doesn't account for when markAsTouched()
is used, and passing a reference to the element around isn't always possible, and it's always inelegant.
Is there a way to use OnPush
and still respond to the form control state (e.g. touched
), or is it just generally painful?
Upvotes: 10
Views: 2382
Reputation: 503
You can overwrite the original markAsTouched
method of your control with a method that also calls markForCheck
:
const originalMarkAsTouched = this.control.markAsTouched;
this.control.markAsTouched = () => {
originalMarkAsTouched.call(this.control);
this.changeDetectorRef.markForCheck();
};
Upvotes: 0
Reputation: 17
You can listen for status changes and then call markForCheck()
to update the view:
constructor(changeDetectorRef: ChangeDetectorRef) {
this.formGroup.statusChanges.subscribe(status => changeDetectorRef.markForCheck());
}
UPDATE: Since I can't comment, I will update this answer.
You are right about statusChanges. and of course you need to subscribe to statusChanges, it was a mistake.
I think we missed a point here. In CheckOnce
mode (OnPush), Angular will check for changes after DOM events (including blur), so the view should be updated and the message you metioned (*ngIf="control.touched && control.invalid"
) should work.
But if you call markAsTouched()
in the code will not check for changes until you call markForCheck()
.
Here is a working example: https://stackblitz.com/edit/angular-6-reactive-form-validation-touched-sjhijt
Upvotes: 1
Reputation: 57939
I do not know if you are looking for the new way to create a ReactiveForm using the new FormGroup directly. Sorry if I did not understand your question. e.g.
//before
this.myForm=this.formBuilder({
control1:''
})
//after
this.myForm=new FormGroup({
control1:new FormControl(''),
},{ updateOn: 'blur' })
Upvotes: 0