我正在关注创建自定义表单控件的Angular Material网站上的
this tutorial.在有验证错误时,教程中没有关于如何遵守表单控制错误的示例.
定制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,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; }
然后我将它的控件属性绑定到内部mat-select控件中.
<mat-select [placeholder]="placeholder" #select [formControl]="control">
然后我在ngDoCheck中调用this.select.updateErrorState.
这是StackBlitz的链接:
https://stackblitz.com/edit/angular-c4ufpp
是否有更好或更标准的方法?
您可以实现验证器接口.
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,multi: true,} ] }) validate(c: AbstractControl): ValidationErrors | null { ... put your validation check in here and return null if it´s valid }