Daniel Schaffer
Daniel Schaffer

Reputation: 57852

Showing Validation messages with Reactive Forms and ChangeDetectionStrategy.OnPush

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

Answers (3)

slim
slim

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

WaseemDev
WaseemDev

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

Eliseo
Eliseo

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

Related Questions