Angular Reactive Forms - 实现输入组件包装器的最佳方式?

Sum*_*mmy 6 angular-material angular angular-reactive-forms

我试图解决的任务:

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

我的意思的例子:

而不必编写以下模板:

<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>
Run Code Online (Sandbox Code Playgroud)

我想写:

<form [formGroup]="myForm">
    <my-input-component [form]="myForm" [myFormControl]="email" [myFormControlName]="'email'" [label]="'Email'"></my-input-component>
</form>
Run Code Online (Sandbox Code Playgroud)

我的输入组件看起来像:

<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>
Run Code Online (Sandbox Code Playgroud)

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

在网上搜索后,我不断遇到NG_CONTROL_VALUE_ACCESSOR,并且有点困惑是否可以或应该在我的场景中使用它。

我不打算让这些组件成为“自定义”,即使用滑块作为表单控件或类似性质的东西,而只是希望“包装器”来节省一些时间。

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

Rit*_*hie 6

正如您已经发现的那样,实现此目的的推荐方法是实现ControlValueAccessor接口。该界面是专门为创建自定义表单控件而创建的。它将在您的可重用组件和 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() {}
}
Run Code Online (Sandbox Code Playgroud)

模板

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

您可以查看这篇文章在 Angular 中创建自定义表单组件以获取更多详细信息。