Home > Back-end >  Custom Common Input Component - Validation Errors not working as expected
Custom Common Input Component - Validation Errors not working as expected

Time:05-18

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).

enter image description here

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.

  • Related