Home > Software design >  Angular Reusable mat form field
Angular Reusable mat form field

Time:06-16

In my Angular application, I have a lot of reactive forms with text inputs that all need Error messages, which is a lot of duplicated code. I wanted to create a custom component for the mat form field, but I am struggling to make it work. This is my template:

<mat-form-field fxLayout="column" fxLayoutAlign="start stretch">
  <mat-label>{{label}}</mat-label>
  <input matInput type="{{inputType}}" autocomplete="username" [formControl]="formControl">
  <mat-error *ngIf="formControl.touched && formControl.errors?.required">
    Bitte geben Sie den {{label}} an!
  </mat-error>
  <mat-error *ngIf="formControl.touched && formControl.errors?.maxlength">
    Der {{label}} darf nicht mehr als {{maxLength}} Zeichen haben!
  </mat-error>
  <mat-error *ngIf="formControl.touched && formControl.errors?.minlength">
    Der {{label}} darf nicht weniger als {{minLength}} Zeichen haben!
  </mat-error>
</mat-form-field>
<ng-container *ngIf="formControl.touched && formControl.invalid">
  <br/>
</ng-container>

The component:

export class FormFieldComponent {

  @Input() formControl: FormControl;

  @Input() inputType: "color" | "date" | "datetime-local" |
"email" | "month" | "number" | "password" | "search" |
"tel" | "text" | "time" | "url" | "week" = "text"

  @Input() appearance: 'legacy' | 'fill' | 'standard' | 'outline' = 'standard';

  @Input() label: string;

  @Input() minLength: number;

  @Input() maxLength: number;
}

In my Form I want to call the component like this:

<mat-card >
    <form [formGroup]="form" (ngSubmit)="login()">
      <mat-card-title style="text-align: center">Login</mat-card-title>
      <mat-card-content fxLayout="column" fxLayoutAlign="start stretch">
        <app-form-field [formControl]="form.controls.userName" [maxLength]="userNameMaxLength" [minLength]="userNameMinLength" [label]="'Benutzername'"></app-form-field>
        <app-form-field [formControl]="form.controls.password" [maxLength]="passwordMaxLength" [minLength]="passwordMinLength" [label]="'Passwort'" [inputType]="'password'"></app-form-field>
        <ng-container *ngIf="loginFailed && formWasSubmitted">
          <br>
          <mat-error>
            Authentifizierung fehlgeschlagen.
            Bitte überprüfen Sie ihren
            Benutzernamen und ihr Password.
          </mat-error>
          <br>
        </ng-container>
        <div fxLayout="column" fxLayoutAlign="start center">
          <button type="submit" mat-raised-button color="primary">Login</button>
        </div>
      </mat-card-content>
    </form>
  </mat-card>

The problem is that in the console I get the following error:

core.mjs:6485 ERROR Error: No value accessor for form control with unspecified name attribute
at _throwError (forms.mjs:1785:11)
at setUpControl (forms.mjs:1576:13)
at FormControlDirective.ngOnChanges (forms.mjs:5126:13)
at FormControlDirective.rememberChangeHistoryAndInvokeOnChangesHook

CodePudding user response:

It's a problem with the "name" of the input formControl, you can use some like

@Input('control') formControl: FormControl;

and use

<app-form-field [control]="control"..>

BTW: it's unnecesary check if touched in a mat-error (by defect a mat-error only show if the formControl is touched) so, e.g. is enought

<mat-error formControl.errors?.minlength">
    Der {{label}} darf nicht weniger als {{minLength}} Zeichen haben!
</mat-error>
  • Related