角形材料反应形式模式-如何使用ControlValueAccessor为该模式制作组件

时间:2019-01-21 11:14:59

标签: angular angular-reactive-forms angular-forms angular-material-6 controlvalueaccessor

使用棱角材料mat-form-field和反应形式。在一个项目中,我有一个类似这样的重复模式

// ts
this.formGroup = this.formBuilder.group({
    name: ['', ServerValidation]
})

<!-- html -->
<div [formGroup]="formGroup">
  <mat-form-field>
    <input
      matInput
      formControlName="name"
      [placeholder]="'Name'"
      name="name"
     />
    <mat-error
     *ngIf="
       formGroup
       .get('name')
       .hasError('serverValidation')
       "
      >
      {{
       formGroup
       .get("name")
       .getError("serverValidation")
      }}
     </mat-error>
   </mat-form-field>
</div>

这是一个很高的层次-接受我可以从服务器接收验证错误-如何在组件中重复此http模板模式?我有一种预感,我应该利用ControlValueAccessor-但不知道该怎么做。

我想象的实现可能看起来像这样

<!-- html -->
<div [formGroup]="formGroup">
  <serverValidatedInput formControlName="'name'">
    <mat-error>error message for client side validation</mat-error>
  </serverValidatedInput>
</div>

因此,从本质上讲,我希望像常规材料输入(或多或少)一样使用此自定义组件,只是默认情况下它带有服务器验证错误。谁能给我一些指导-谢谢。 :)

1 个答案:

答案 0 :(得分:0)

有两种方法可以做到这一点-一种简单的方法和一种困难的方法。困难的方法是实现ControlValueAccessor,这为您提供了更多使用组件的灵活性。简单的方法是将事物通过您的组件传递到内部的实际表单元素。如果您不需要灵活使用此组件,请采用简单的方法。

不过,首先,您需要摆脱在mat-error之外使用mat-form-control的想法。它根本行不通,并且您不需要它就行。将其保留在表单字段中,并为其提供内容。除此之外,将错误逻辑应用于mat-error的内容,而不是mat-error本身。请记住,您不需要逻辑来显示 mat-error-当表单控件出现错误时,表单字段会自动进行处理。您只需要逻辑来确定错误 content 应该是什么。

mat-form-field的简单包装看起来像这样:

my-form-field.html

<mat-form-field>
  <input matInput type="text" [placeholder]="placeholder" [formControl]="myFormControl" required>
  <mat-error>
    <ng-content></ng-content>
  </mat-error>
</mat-form-field>

my-form-field.ts

import {Component, Input} from '@angular/core';
import {FormControl} from '@angular/forms';

@Component({
  selector: 'my-form-field',
  templateUrl: 'my-form-field.html'
})
export class MyFormField {
  @Input() myFormControl: FormControl;
  @Input() placeholder: string;
}

用法

custom-form-field-example.html

<form [formGroup]="formGroup">
  <my-form-field placeholder="Name" [myFormControl]="formGroup.get('name')">
    <ng-container *ngIf="formGroup.get('name').hasError('required')">
     This field is required
    </ng-container>
    <ng-container *ngIf="formGroup.get('name').hasError('serverValidation')">
      Server validation failed
    </ng-container>
  </my-form-field>
</form>

custom-form-field-example.ts

import {Component} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {ServerValidation} from '...';

@Component({
  selector: 'custom-form-field-example',
  templateUrl: 'custom-form-field-example.html'
})
export class CustomFormFieldExample {
  formGroup: FormGroup;

  constructor(formBuilder: FormBuilder) {
    this.formGroup = formBuilder.group({
      name: ['', [Validators.required, ServerValidation]]
    });
  }
}