Reputation: 2324
I have my error handling for mat-input like this
<mat-form-field>
<input formControlName="title" matInput placeholder="Title*" />
<mat-error *ngIf="addNewForm.get('title').errors?.required">
Can not be empty
</mat-error>
<mat-error *ngIf="addNewForm.get('title').errors?.minlength">
Min length is 1 character
</mat-error>
<mat-error *ngIf="addNewForm.get('title').errors?.maxlength">
Max length is 255 characters
</mat-error>
</mat-form-field>
<mat-form-field>
<input formControlName="name" matInput placeholder="Name*" />
<mat-error *ngIf="addNewForm.get('name').errors?.required">
Can not be empty
</mat-error>
<mat-error *ngIf="addNewForm.get('name').errors?.minlength">
Min length is 1 character
</mat-error>
<mat-error *ngIf="addNewForm.get('name').errors?.maxlength">
Max length is 255 characters
</mat-error>
</mat-form-field>
How to handle this directly in component, soo instead of writing all of this errors manually, check all in component and dynamically set errors, something like this
<mat-form-field>
<input formControlName="title" matInput placeholder="Title*" />
<mat-error>{{ someError }}</mat-error>
</mat-form-field>
<mat-form-field>
<input formControlName="name" matInput placeholder="Name*" />
<mat-error>{{ someError }}</mat-error>
</mat-form-field>
Here is component
this.addNewUserForm = this.formBuilder.group({
title: [
"",
[
Validators.required,
Validators.minLength(1),
Validators.maxLength(255),
noWhitespaceValidator
]
],
name: [
"",
[
Validators.required,
Validators.minLength(4),
Validators.maxLength(255),
noWhitespaceValidator
]
]
});
Upvotes: 0
Views: 11886
Reputation: 1640
You can write a getter function which returns simply the error message. Like this:
get errorMessage(): string {
const form: FormControl = (this.addNewUserForm.get('title') as FormControl);
return form.hasError('required') ?
'Required error message' :
form.hasError('maxlength') ?
'Max length error' :
form.hasError('minlength') ?
'Min length error' :
form.hasError('nowhitespaceerror') ?
'No white space error' : '';
}
After this you simply use this method like a variable in template:
<mat-error>{{ errorMessage }}</mat-error>
Or a simple solution based on this example: here.
export class InputErrorExample {
constructor(private formBuilder: FormBuilder) {}
errorMessages = {
maxlength: 'max',
minlength: 'min',
email: 'email'
};
addNewUserForm = this.formBuilder.group({
title: [
"",
[
Validators.required,
Validators.minLength(1),
Validators.maxLength(255),
Validators.email
// noWhitespaceValidator
]
]
});
errors(ctrl: FormControl): string[] {
return ctrl.errors ? Object.keys(ctrl.errors) : [];
}
}
<form class="example-form">
<mat-form-field class="example-full-width">
<input matInput placeholder="Email" [formControl]="addNewUserForm.get('title')"
[errorStateMatcher]="matcher">
<mat-hint>Errors appear instantly!</mat-hint>
<mat-error>
<ng-container *ngFor="let error of errors(addNewUserForm.get('title'))">
{{ errorMessages[error] }} <br>
</ng-container>
</mat-error>
</mat-form-field>
</form>
Upvotes: 6
Reputation: 11934
Here is one approach:
Listen to the statusChanges
observable of your FormControl
instance and when it emits, get its first error.
const titleCtrl = this.addNewUserForm.get('title');
const titleErr$ = titleCtrl.statusChanges
.pipe(
filter(status => status === 'INVALID'),
map(() => {
if (!titleCtrl.errors) {
return null;
}
// Returning the first error
for (const errName in titleCtrl.errors) {
return titleCtrl.errors[errName];
}
}),
filter(err => !!err)
)
Now, it depends on your use-case.
If you need to use your error only once in the template, you can use the async pipe.
<mat-form-field>
<input formControlName="title" matInput placeholder="Title*" />
<mat-error>{{ titleErr$ | async }}</mat-error>
</mat-form-field>
If you need to use the error in multiple places or if you need to perform the same logic for multiple FormControl
s, you can either subscribe in the component(imperative way) or you can find a way to combine all the errors and keep the subscription in the view(reactive way).
Bear in mind that if you subscribe in the component class, you'll have to unsubscribe.
Upvotes: 1