Как составить Angular Компоненты управления формой материала

В приведенном ниже коде показан элемент формы автозаполнения, который позволяет выбирать состояние в США.

  <mat-form-field class="example-full-width">
    <input matInput placeholder="State" aria-label="State" [matAutocomplete]="auto" [formControl]="stateCtrl">
    <mat-autocomplete #auto="matAutocomplete">
      <mat-option *ngFor="let state of filteredStates | async" [value]="state.name">
        <img style="vertical-align:middle;" aria-hidden src="{{state.flag}}" height="25" />
        <span>{{ state.name }}</span> |
        <small>Population: {{state.population}}</small>
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>

Однако, если в моем приложении у меня есть множество мест, где требуется этот тип ввода, тогда было бы целесообразно превратить это в компонент (директива?), где все шаблоны не нужно повторять. Тем не менее, я все равно хотел бы использовать это в формах, управляемых шаблонами или с помощью модели, и позволять заполнителям, валидации и т.д. Варьироваться компонентом контейнера.

Что такое простой и надежный способ достичь этого?

Я пробовал общие подходы, рекомендованные для Angular, но они не учитывают различные требования к материалу Angular. Например. Нужно реализовать MatFormFieldControl. Руководство, представленное Angular Материалом, больше направлено на создание нового элемента управления формой с использованием примитивных элементов, а не на использование/обертку существующих элементов управления формой Angular.

Цель состоит в том, чтобы иметь возможность сделать что-то вроде этого в форме:

<mat-form-field>
    <lookup-state placeholder="State of Residence" required="true" formControlName="resState">
    </lookup-state>
</mat-form-field>

Ответ 1

Я собираюсь вставить свой пример компонента, используя Angular Материал. Я создал пользовательский компонент ввода (два случая: простой ввод или автозаполнение):

это мой Input.component.html

<mat-form-field color="accent" [hideRequiredMarker]="true" [class.mat-form-field-invalid]="hasErrors">
  <ng-container *ngIf="autocomplete">
    <input matInput [matAutocomplete]="auto" [type]="type" [placeholder]="placeholder" [disabled]="isDisabled" [value]="innerValue" (input)="autocompleteHandler($event)" (blur)="autocompleteBlur($event)">
    <mat-autocomplete #auto [displayWith]="displayText" (optionSelected)="updateOption($event)">
      <mat-option *ngFor="let choice of autocompleteChoices | async" [value]="choice">{{ choice.text }}</mat-option>
    </mat-autocomplete>
  </ng-container>
  <input *ngIf="!autocomplete" matInput [type]="type" [placeholder]="placeholder" [disabled]="isDisabled" [value]="innerValue" (input)="inputHandler($event)" (blur)="setTouched()">
</mat-form-field>

Ответ 2

У меня была такая же проблема, если вы хотите создать компонент-оболочку для автозаполнения. Ниже приведена моя реализация, которая работает в реактивных и управляемых шаблонами формах. Для этого вам необходимо реализовать ControlValueAccessor. Если вы также имеете некоторую проверку, которую хотите переместить в компонент, вы также можете реализовать интерфейс Validator.

У меня возникла проблема с тем, что mat-form-field не был помечен как недопустимый, хотя элемент управления формами фактически недействителен. Это комментарий к проблеме "Стили не применяются, если FormField обернут настраиваемым компонентом" и этот связанный plunker помог мне исправить это.

autocomplete.component.html:

<mat-form-field>
  <input #input matInput type="text" class="form-control" [matAutocomplete]="autocomplete" (input)="valueChanged($event)" [readonly]="readonly"
    (focus)="$event.target.select()" (blur)="onTouched()">
  <mat-autocomplete #autocomplete="matAutocomplete" [displayWith]="displayFunction" (optionSelected)="onOptionSelected($event)">
    <mat-option *ngFor="let option of filteredOptions" [value]="option">
        {{ displayFunction(option) }}
    </mat-option>
  </mat-autocomplete>
</mat-form-field>