簡體   English   中英

Angular Material - 帶有錯誤狀態的自定義反應式表單控件

[英]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.updateErrorStatengDoCheck

這是 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM