Я пытаюсь написать общий компонент ввода для 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
не работает, как в предыдущем примере.
Я ожидаю, что в обоих полях ниже должно отображаться «Требуется имя». сообщение об ошибке для обоих полей, когда ввод пуст. Но я вижу это только для второго поля (которое не использует мой общий компонент).
Я создал рабочий пример в StackBlitz (https://stackblitz.com/edit/add-angular-material-yph1vt?file=src/app/app.component.ts)
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
?
Поскольку я действительно не хочу реализовывать свой собственный ввод, я просто хочу использовать matInput
. И просто иметь общий HTML для меток, подсказок, сообщений об ошибках.
Я думаю, что это ДОЛЖНО работать без реализации ControlValueAccessor
- просто получить formControl из вашего компонента и передать его в нужное место. Но я никогда этого не делал, так что вы должны проверить это сами.
Похоже, что класс ng-invalid не добавлен на вход. Компонент не знает MatError, если вы измените тег на
<p>
или что-то в этом роде, он там есть. И необходимый scss для стилизации класса ng-invalid не загружается при ручной установке. Я не знаю, как это исправить. Но мне любопытно, и я займусь расследованием, когда у меня будет больше времени.