I am trying to write up a common input component for Material Angular, so I don't have to duplicate 20 lines of HTML code for every single field. But I am having issues getting the mat-error
to show the validation message.
So this is the code I had in MyFormComponent
:
<div >
<mat-form-field appearance="fill" hintLabel="Max 10 characters">
<mat-label> Name Old (works) </mat-label>
<input matInput type="text" formControlName="nameOld" />
<mat-hint align="end">the/10</mat-hint>
<mat-error *ngIf=" (formModal.get('nameOld').dirty || formModal.get('nameOld').touched) &&
formModal.get('nameOld').errors && formModal.get('nameOld').errors['required'] ">
Name Old is required.
</mat-error>
</mat-form-field>
</div>
Now I've moved this to a custom component CommonInputComponent
as the following:
HTML:
<div >
<mat-form-field appearance="fill" hintLabel="Max 10 characters">
<mat-label>{{ fieldInfo.label }}</mat-label>
<input
matInput
[type]="fieldInfo.type"
[placeholder]="fieldInfo.placeholder"
[value]="value"
(input)="onChange($event.target.value)"
(blur)="onTouched()"
/>
<mat-hint align="end">{{ ngControl.value?.length || 0 }}/10</mat-hint>
<mat-error
*ngIf="
(ngControl.dirty || ngControl.touched) &&
ngControl.errors &&
ngControl.errors['required']
"
>Name is required.</mat-error
>
</mat-form-field>
<pre>{{ ngControl.errors | json }}</pre>
<pre>{{ { dirty: ngControl.dirty, touched: ngControl.touched } | json }}</pre>
</div>
and then I try to use it in my Form MyFormComponent
as:
<app-common-input
formControlName="name"
[fieldInfo]="{ label: 'name', name: 'name', type: 'text' }"
></app-common-input>
All the bindings seem to work fine, the properties are updated across both the parent and child components, but the only issue I am facing is that mat-error
doesn't seem to work as it did in the previous example.
What I am expecting in both fields below is that it should show the "Name is required." error message for both fields when the input is blank. But I only see it for the 2nd field (which is not using my common component).
I have created a working example in StackBlitz (https://stackblitz.com/edit/add-angular-material-yph1vt?file=src/app/app.component.ts)
CodePudding user response:
The mat-input
inside your app-common-input
is not bound to any FormControl
. You're working around it by binding value
, onChange
and onTouched
events to the <input>
, but none of that actually passes the information about validations and state of the FormControl
itself.
And the way that mat-error
works inside of a mat-form-field
, it needs to know that the bound FormControl
has some errors to display.
Since what you seem to be looking for is kind of a "pass-through" ControlValueAccessor
, you can just replace this part:
<input
matInput
[type]="fieldInfo.type"
[placeholder]="fieldInfo.placeholder"
[value]="value"
(input)="onChange($event.target.value)"
(blur)="onTouched()"
/>
with this:
<input
matInput
[type]="fieldInfo.type"
[placeholder]="fieldInfo.placeholder"
[formControl]="ngControl.control"
/>
This means that everything that happens to your components will be passed down to the internal matInput
and vice-versa.