Пользовательский общий компонент ввода — ошибки проверки не работают должным образом

Я пытаюсь написать общий компонент ввода для Material Angular, поэтому мне не нужно дублировать 20 строк HTML-кода для каждого отдельного поля. Но у меня возникли проблемы с получением mat-error для отображения сообщения проверки.

Итак, это код, который у меня был в MyFormComponent:

<div class="form-group">

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

Теперь я переместил это в пользовательский компонент CommonInputComponent следующим образом:

HTML:

<div class="form-group">
  <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>

а затем я пытаюсь использовать его в своей форме MyFormComponent как:

<app-common-input
  formControlName="name"
  [fieldInfo]="{ label: 'name', name: 'name', type: 'text' }"
></app-common-input>

Все привязки работают нормально, свойства обновляются как в родительском, так и в дочернем компонентах, но единственная проблема, с которой я столкнулся, заключается в том, что mat-error не работает, как в предыдущем примере.

Я ожидаю, что в обоих полях ниже должно отображаться «Требуется имя». сообщение об ошибке для обоих полей, когда ввод пуст. Но я вижу это только для второго поля (которое не использует мой общий компонент).

enter image description here

Я создал рабочий пример в StackBlitz (https://stackblitz.com/edit/add-angular-material-yph1vt?file=src/app/app.component.ts)

Похоже, что класс ng-invalid не добавлен на вход. Компонент не знает MatError, если вы измените тег на <p> или что-то в этом роде, он там есть. И необходимый scss для стилизации класса ng-invalid не загружается при ручной установке. Я не знаю, как это исправить. Но мне любопытно, и я займусь расследованием, когда у меня будет больше времени.

H3AR7B3A7 17.05.2022 01:58
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Обработка ошибок при выполнении HTTP-запросов в JavaScript.
Обработка ошибок при выполнении HTTP-запросов в JavaScript.
Каждый проект должен выполнять HTTP-запросы, и, конечно, некоторые из этих запросов могут содержать ошибки. Нам нужно знать, как обрабатывать эти...
Включение UTF-8 в jsPDF с помощью Angular
Включение UTF-8 в jsPDF с помощью Angular
Привет, разработчики, я предполагаю, что вы уже знаете, как экспортировать pdf через jsPDF. Если ответ отрицательный, то вы можете ознакомиться с моей...
1
1
35
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

mat-input внутри вашего app-common-input не привязан ни к какому FormControl. Вы работаете над этим, привязывая события value, onChange и onTouched к <input>, но ни одно из них на самом деле не передает информацию о проверках и состоянии самого FormControl.

И то, как mat-error работает внутри mat-form-field, должно знать, что связанный FormControl имеет некоторые ошибки для отображения.

Поскольку то, что вы, кажется, ищете, является своего рода «сквозным» ControlValueAccessor, вы можете просто заменить эту часть:

<input
  matInput
  [type]="fieldInfo.type"
  [placeholder]="fieldInfo.placeholder"
  [value]="value"
  (input)="onChange($event.target.value)"
  (blur)="onTouched()"
/>

с этим:

<input
  matInput
  [type]="fieldInfo.type"
  [placeholder]="fieldInfo.placeholder"
  [formControl]="ngControl.control"
/>

Это означает, что все, что происходит с вашими компонентами, будет передаваться внутренним matInput и наоборот.

Ничего себе, это имеет смысл. Я знал, что делаю что-то не так, но первый раз, когда работал в новом Angular, не мог этого отследить. Исходя из этого, просто дополнительный вопрос. Мне действительно нужно внедрять ControlValueAccessor в CommonInputComponent?

Dawood Awan 17.05.2022 12:42

Поскольку я действительно не хочу реализовывать свой собственный ввод, я просто хочу использовать matInput. И просто иметь общий HTML для меток, подсказок, сообщений об ошибках.

Dawood Awan 17.05.2022 12:45

Я думаю, что это ДОЛЖНО работать без реализации ControlValueAccessor - просто получить formControl из вашего компонента и передать его в нужное место. Но я никогда этого не делал, так что вы должны проверить это сами.

TotallyNewb 17.05.2022 13:14

Другие вопросы по теме