Reputation: 401
I have some input fields with different validation rules set on them. But I also want to add some validation to all the fields at once, when submitting, or make submit button disabled, if there are any errors above.
However, I haven't put all my inputs inside form tag from the beginning and have kind of trouble with that right now. I am new to all of this, so can you please help me? Is there any way to solve it, without recreating all the form? :(
I've tried adding:
<form #stepOneForm="ngForm">
<button type="submit [disabled]="!stepOneForm.form.valid" mat-button matStepperNext>Go to next step</button>
But it didnt help...
My code looks as below:
HTML
<!-- Name -->
<mat-form-field class="dcp-input-field">
<input matInput placeholder="Name" [formControl]="name" [errorStateMatcher]="matcher">
<mat-hint>Please enter your name</mat-hint>
<mat-error *ngIf="name.hasError('required')">
This is <strong>required</strong> field
</mat-error>
</mat-form-field>
<!-- DoB -->
<mat-form-field class="dcp-input-field">
<input matInput [matDatepicker]="dp" placeholder="Date of Birth" [formControl]="dob" [errorStateMatcher]="matcher">
<mat-datepicker-toggle matSuffix [for]="dp"></mat-datepicker-toggle>
<mat-datepicker #dp></mat-datepicker>
<mat-hint>Please enter your date of birth</mat-hint>
<mat-error *ngIf="dob.hasError('required')">
This is <strong>required</strong> field
</mat-error>
</mat-form-field>
<!-- PolicyNo -->
<mat-form-field class="dcp-input-field">
<input matInput placeholder="Policy number" [formControl]="policyNo" [errorStateMatcher]="matcher">
<mat-hint>Please enter your Policy number</mat-hint>
<mat-error *ngIf="policyNo.hasError('required')">
This is <strong>required</strong> field
</mat-error>
<mat-error *ngIf="policyNo.hasError('minlength')">
The value is <strong>too short</strong>
</mat-error>
</mat-form-field>
TS
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(
control: FormControl | null,
form: FormGroupDirective | NgForm | null
): boolean {
const isSubmitted = form && form.submitted;
return !!(
control &&
control.invalid &&
(control.dirty || control.touched || isSubmitted)
);
}
}
name = new FormControl("", [Validators.required]);
dob = new FormControl("", [Validators.required]);
policyNo = new FormControl("", [
Validators.required,
Validators.minLength(6)
]);
matcher = new MyErrorStateMatcher();
Thank you and sorry for noob question! ;)
Upvotes: 2
Views: 18771
Reputation: 468
HTML
wrap all your inputs in form
tag
instead
<form #stepOneForm="ngForm">
do
<form (ngSubmit)="onSubmit()" [formGroup]="myForm"></form>
instead
<input matInput placeholder="Name" [formControl]="name" [errorStateMatcher]="matcher">
do
<input matInput placeholder="Name" formControlName="name">
that goes with all input formControlName
not [formControl]
instead
<button type="submit [disabled]="!stepOneForm.form.valid" mat-button matStepperNext>Go to next step</button>
do
<button type="submit" [disabled]="myForm.invalid" mat-button matStepperNext>Go to next step</button>
--when you trying to show error msg to access to input errors validation
instead
name.hasError('required')
do
myForm.get('name').errors?.required
//or
myForm.get('name').errors['required']
both ways to check error gonna work the main different between them using safe navigation operator (?.)
that's like you saying "hay angular check first if there's error (not unll or undefined) then check the type of error required, maxLength...etc" main purpose to prevent javascript from raising error cannot read property
for reference safe navigation operator
or (another validation case)
*ngIf="myForm.get('name').invalid && myForm.get('name').touched"
TS
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
@Component({
selector: '...',
templateUrl: '...',
styleUrls: ['...']
})
export class myApp implements OnInit {
myForm: FormGroup;
ngOninit() {
this.myForm = new FormGroup({
'name': new FormControl(null, Validators.required),
'policyNo': new FormControl(null, validators.minLength(5))
// the rest of inputs with the same approach
});
}
onSubmit() {
// when submit the form do something
}
}
you using here reactive forms
not template driven
each has different use make sure you use the correct way for both because you mess the reactive approach
with template driven approach
that what messed up everything.
recommendation read Reqctive Froms Template Forms
Upvotes: 8