Angular反应形式-实施输入组件包装的最佳方法?

时间:2019-07-10 22:43:12

标签: angular angular-reactive-forms material

我要解决的任务:

创建可重复使用的输入组件包装器,以节省编写表单模板时的时间。

我的意思示例:

无需编写以下模板:

<form [formGroup]="myForm">
  <mat-form-field>
    <input matInput placeholder="Email" [formControl]="email" required>
    <mat-error *ngIf="email.invalid">{{getErrorMessage()}}</mat-error>
  </mat-form-field> 
<form>

我想写:

<form [formGroup]="myForm">
    <my-input-component [form]="myForm" [myFormControl]="email" [myFormControlName]="'email'" [label]="'Email'"></my-input-component>
</form>

我的输入组件的外观如下:

<mat-form-field [formGroup]="form">
    <input
        matInput
        type="text"
        [attr.inputmode]="inputMode"
        [placeholder]="label"
        [formControlName]="myFormControlName"
    />
    <mat-error class="errors" *ngIf="myFormControl.invalid">
        <div>{{ getError() }}</div>
    </mat-error>
</mat-form-field>

这按原样工作,但我不知道这是否是将FormGroup和FormControls作为绑定传递的好方法。

在线搜索后,我不断遇到 NG_CONTROL_VALUE_ACCESSOR ,是否可以在我的场景中使用它感到有些困惑。

从使用滑块作为表单控件或类似性质的意义上讲,我不希望这些组件是“自定义的”,而只是希望“包装器”节省一些时间。

有关该主题的任何建议或建议,将不胜感激!

1 个答案:

答案 0 :(得分:0)

推荐使用的方法是实现ControlValueAccessor interface,就像您已经发现的那样。该接口是专门为创建自定义表单控件而创建的。它将在您的可重用组件和Forms API之间建立一座桥梁。

这是带有标签的可重用输入字段的一个小示例。您也可以在此模板中添加错误消息。

组件

import { Component, OnInit, Input, Self, Optional } from '@angular/core';
import { ControlValueAccessor, NgControl } from '@angular/forms';

@Component({
  selector: 'custom-input',
  templateUrl: './custom-input.component.html',
  styleUrls: ['./custom-input.component.css']
})
export class CustomInputComponent implements OnInit, ControlValueAccessor {
  @Input() disabled: boolean;
  @Input() label: string;
  @Input() placeholder: string = '';
  @Input() type: 'text' | 'email' | 'password' = 'text';

  value: any = '';

  constructor(
    // Retrieve the dependency only from the local injector,
    // not from parent or ancestors.
    @Self()
    // We want to be able to use the component without a form,
    // so we mark the dependency as optional.
    @Optional()
    private ngControl: NgControl
  ) {
    if (this.ngControl) {
      this.ngControl.valueAccessor = this;
    }
  }

  ngOnInit() {}

  /**
   * Write form value to the DOM element (model => view)
   */
  writeValue(value: any): void {
    this.value = value;
  }

  /**
   * Write form disabled state to the DOM element (model => view)
   */
  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  /**
   * Update form when DOM element value changes (view => model)
   */
  registerOnChange(fn: any): void {
    // Store the provided function as an internal method.
    this.onChange = fn;
  }

  /**
   * Update form when DOM element is blurred (view => model)
   */
  registerOnTouched(fn: any): void {
    // Store the provided function as an internal method.
    this.onTouched = fn;
  }

  private onChange() {}
  private onTouched() {}
}

模板

<label>{{ value }}</label>
<input [type]="type"
       [placeholder]="placeholder"
       [value]="value"
       [disabled]="disabled"
       (input)="onChange($event.target.value)"
       (blur)="onTouched()" />

您可以查看本文Creating a custom form component in Angular以获取更多详细信息。