Я следую этому руководству с веб-сайта Angular Material о создании пользовательского элемента управления формы.В этом руководстве нет примеров того, как соблюдать ошибки управления формой при наличии ошибок проверки.
custom-text.component.html
<mat-form-field class="example-full-width">
<mat-select [placeholder]="placeholder" #select [formControl]="control">
<mat-option *ngFor="let food of foods" [value]="food">
{{food}}
</mat-option>
</mat-select>
<mat-error>This is required.</mat-error>
</mat-form-field>
custom-text.component.ts
import { Component, ViewChild, HostBinding, Input, ChangeDetectionStrategy, Optional, Self, DoCheck, OnInit, NgZone } from '@angular/core';
import { ControlValueAccessor, NgControl, NgForm, FormGroupDirective, FormControlDirective, FormControlName, FormControl, FormBuilder } from '@angular/forms';
import { MatFormFieldControl, MatSelect, CanUpdateErrorState, ErrorStateMatcher } from '@angular/material';
@Component({
selector: 'custom-text',
templateUrl: './custom-text.component.html',
styleUrls: [
'./custom-text.component.scss'
],
providers: [
{
provide: MatFormFieldControl,
useExisting: CustomTextComponent
}
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CustomTextComponent implements ControlValueAccessor, OnInit, DoCheck {
@Input()
foods: string[];
@Input()
get errorStateMatcher(): ErrorStateMatcher {
return this.select.errorStateMatcher;
}
set errorStateMatcher(val) {
this.select.errorStateMatcher = val;
}
@Input()
get placeholder() {
return this.select.placeholder;
}
set placeholder(plh) {
this.select.placeholder = plh;
this.stateChanges.next();
}
@Input()
get value() {
return this.select.value;
}
set value(val) {
this.select.value = val;
this.stateChanges.next();
}
@ViewChild('select')
select: MatSelect;
control: FormControl;
constructor(
@Optional() @Self() ngControl: NgControl,
@Optional() private _controlName: FormControlName) {
if (ngControl) {
ngControl.valueAccessor = this;
}
}
ngOnInit(): void {
this.control = this._controlName.control;
}
ngDoCheck(): void {
this.select.updateErrorState();
}
writeValue(obj: any): void {
this.value = obj;
}
registerOnChange(fn: any): void {
this.select.registerOnChange(fn);
}
registerOnTouched(fn: any): void {
this.select.registerOnTouched(fn);
}
setDisabledState?(isDisabled: boolean): void {
this.select.setDisabledState(isDisabled);
}
}
app.component.html
<div style="text-align:center">
<form class="example-form" [formGroup]="myForm" (submit)="submitForm()">
<custom-text [foods]="[null, 'burger', 'spaghetti', 'fries']"
formControlName="selectedFood"
[errorStateMatcher]="matcher"></custom-text>
<button>Submit</button>
</form>
</div>
По сути, я вставил FormControlName
экземпляр впользовательский элемент управления.
constructor(
@Optional() private _controlName: FormControlName) {
....
ngOnInit(): void {
this.control = this._controlName.control;
}
Затем я связываю его свойство control
с внутренним элементом управления mat-select
.
<mat-select [placeholder]="placeholder" #select [formControl]="control">
Затем я вызываю this.select.updateErrorState
внутри ngDoCheck
.
Вот ссылка на StackBlitz: https://stackblitz.com/edit/angular-c4ufpp
Есть ли лучший или более стандартный способ для этого?