[英]Angular Material - Custom Reactive Form Control with Error State
I am following this tutorial from the Angular Material website about creating a custom form control.我正在关注来自 Angular Material 网站的有关创建自定义表单控件的教程。 There are no examples in the tutorial regarding how to respect form control errors when there are validation errors.本教程中没有关于如何在出现验证错误时尊重表单控件错误的示例。
custom-text.component.html自定义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自定义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应用程序组件.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>
Basically, I injected FormControlName
instance into the custom control.基本上,我将FormControlName
实例注入到自定义控件中。
constructor(
@Optional() private _controlName: FormControlName) {
....
ngOnInit(): void {
this.control = this._controlName.control;
}
I then bind it's control
property into the inner mat-select
control.然后我将它的control
属性绑定到内部mat-select
控件中。
<mat-select [placeholder]="placeholder" #select [formControl]="control">
I then call this.select.updateErrorState
inside ngDoCheck
.然后我打电话this.select.updateErrorState
内ngDoCheck
。
Here's the link to StackBlitz: https://stackblitz.com/edit/angular-c4ufpp这是 StackBlitz 的链接: https ://stackblitz.com/edit/angular-c4ufpp
Is there is a better or more standard way of this?有没有更好或更标准的方法?
Instead of using the Validator interface, which create the cyclic error dependency, add errorState
in your custom component that checks the ngControl
that was injected into the constructor, like this: 而不是使用创建循环错误依赖项的Validator接口,在自定义组件中添加errorState
,以检查注入构造函数的ngControl
,如下所示:
get errorState() {
return this.ngControl.errors !== null && !!this.ngControl.touched;
}
This makes DoCheck
unnecessary. 这使DoCheck
不必要。 In your parent component, instead of using errorMatcher
, use normal Angular validators, like this: 在父组件中,使用普通的Angular验证器,而不是使用errorMatcher
,如下所示:
selectedFood = new FormControl('burger', [Validators.required]);
You could implement the validator Interface. 您可以实现验证器接口。
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.