Working with the angular reactive form you must have an encounter with markAsTouched()
or markAllAsTouched()
of the reactive forms.
In this tutorial, we will see how I came up with a small solution that how to avoid repeating markAllAsTouched on every submit.
For Angular version lower than 8, Refer this custom custom method to mark all form fields as touched.
markAllAsTouched
If you are using a reactive form of angular you might have some example form in which you may have to call the method on every form submit.
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<input type="email" formControlName="email">
<small *ngIf="group.get('email').hasError('required') && group.get('email').touched">
This field is required
</small>
<input type="password" formControlName="password">
<small *ngIf="group.get('password').hasError('required') && group.get('password').touched">
This field is required
</small>
<button type="submit">Submit</button>
</form>
And in each submit handler you’ve called markAllAsTouched() to cover cases where users didn’t touch one of the fields:
@Component()
export class AppComponent {
public loginForm: FormGroup = new FormGroup({
email: new FormControl('', Validators.required),
password: new FormControl('', Validators.required)
});
public onSubmit(): void {
this.loginForm.markAllAsTouched(); // calling mark as touch every time.
if(this.loginForm.valid) { ... }
}
}
Directive To Mark Form Touched
We can automate this process on every submit by creating a directive that seamlessly does the work for us:
import { Directive, Self, HostListener } from '@angular/core';
import { ControlContainer } from '@angular/forms';
@Directive({
selector: 'form[formGroup]'
})
export class MarkAllTouchedDirective {
@HostListener('submit')
public onSubmit(): void {
this.container.control.markAllAsTouched();
}
constructor(
@Self() private container: ControlContainer
) {}
}
First, we target forms that have the formGroup directive.
Next, we obtain a reference to the FormGroupDirective instance via dependency injection.
The last thing we need to do is register the submit event and call method to mark all form fields as touched.
See Angular Doc on AbstractControl
Make Your Own markAllAsTouched Method
For Angular version lower than 8, FormGroup doesn’t have the method to mark all fields as touched. So we can come up with a custom method as FromHelper.
import { FormGroup } from '@angular/forms';
/**
* Helper Class for FormGroup
*/
export class FormHelper {
/**
* Marks all controls in a FormGroup as touched
* ==> method markAllAsTouched : Available in angular 8 or 8+ version in FormGroup.
* @param {FormGroup} formGroup - The form group to touch
* @public
*/
public markAllAsTouched(formGroup: FormGroup): void {
(Object as any).values(formGroup.controls).forEach((control: any) => {
control.markAsTouched();
if (control.controls) {
this.markAllAsTouched(control);
}
});
}
}
All we have done is called a recursive method to go inside every nested field for form and mark each field individually as touched.