![](/img/trans.png)
[英]Angular 4: reactive form control is stuck in pending state with a custom async validator
[英]Angular Material - Custom Reactive Form Control with Error State
我正在關注來自 Angular Material 網站的有關創建自定義表單控件的教程。 本教程中沒有關於如何在出現驗證錯誤時尊重表單控件錯誤的示例。
自定義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>
自定義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);
}
}
應用程序組件.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
有沒有更好或更標准的方法?
而不是使用創建循環錯誤依賴項的Validator接口,在自定義組件中添加errorState
,以檢查注入構造函數的ngControl
,如下所示:
get errorState() {
return this.ngControl.errors !== null && !!this.ngControl.touched;
}
這使DoCheck
不必要。 在父組件中,使用普通的Angular驗證器,而不是使用errorMatcher
,如下所示:
selectedFood = new FormControl('burger', [Validators.required]);
您可以實現驗證器接口。
import { NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator, Validators } from'@angular/forms';
..other imports
@Component({
...
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => YourComponent),
multi: true
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => YourComponent),
multi: true,
}
]
})
validate(c: AbstractControl): ValidationErrors | null {
... put your validation check in here and return null if it´s valid
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.