Angular:ControlValueAccessor vs @Input - 什么时候用表单?

amo*_*uda 8 angular

ControlValueAccessors 在过去几个月突然出现在我面前,我对为什么或何时应该使用它们而不是@Input与我的反应式表单一起使用感到有些困惑。

这是迄今为止我如何使用反应式表单的示例代码:

@Component({
 selector: 'app-my-component',
 template: `<input [formControl]="form.get('specificControlName')"  />` 
 // or the alternative method of [formGroup]="form" and formControlName="specificControlName"
})
export class MyComponent {
 @Input() form: FormGroup; // passed in formGroup

 ngOnInit() {
  form.valueChanges.pipe(
   // do rxjs magic here
  ).subscribe(value => {
   // do something with the value
  })
 }
}
Run Code Online (Sandbox Code Playgroud)

响应式表单保存表单的状态,因此我甚至可以从父组件访问该状态。我还可以访问所有不同的NgControl属性,如validdisableddirty,和touched

ControlValueAccessors 提供了什么,而这种使用反应式表单的方式没有提供?什么是一些使用情况下,ControlValueAccessors优于工作@Input@Output一般的?

编辑

https://medium.com/angular-in-depth/angular-nested-reactive-forms-using-cvas-b394ba2e5d0d

在本文中,作者提到了以下主要区别:

实现嵌套表单的三种方式:

...

  1. 通过 Input 将 FormGroup 的句柄传递给子组件并在子模板中引用它。有几个很好的教程。

但是使用这种方法的缺点是您将父表单组与子组的表单组紧密绑定。

  1. 使用复合 CVA。

优点:高度可重用,便携。更好的封装(组件的内部表单控件不一定需要对父组件可见)。当您有更多数量的表单模块(通常是一个大型项目)时,最好使用此方法。

缺点:需要实现 CVA 接口会导致样板代码。

这很有趣,但它引发了更多问题:为什么以及何时不希望您的内部表单控件对父级可见?便携是什么意思?

还:

import { Component, OnInit } from '@angular/core';
import { ControlValueAccessor,NG_VALUE_ACCESSOR, NG_VALIDATORS, FormGroup,FormControl, Validator, Validators,AbstractControl, ValidationErrors } from "@angular/forms";

@Component({
  selector: 'app-address-info',
  templateUrl: './address-info.component.html',
  styleUrls: ['./address-info.component.css']
})
export class AddressInfoComponent implements OnInit, ControlValueAccessor {

public addressForm: FormGroup = new FormGroup({
  addressLine: new FormControl("",[Validators.required]),
  areacode: new FormControl('', [Validators.required, Validators.maxLength(5)])
});
  constructor() { }
  ngOnInit() {
  }

  public onTouched: () => void = () => {};

  writeValue(val: any): void {
    val && this.addressForm.setValue(val, { emitEvent: false });
  }
  registerOnChange(fn: any): void {
    console.log("on change");
    this.addressForm.valueChanges.subscribe(fn);
  }
  registerOnTouched(fn: any): void {
    console.log("on blur");
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    isDisabled ? this.addressForm.disable() : this.addressForm.enable();
  }
}

Run Code Online (Sandbox Code Playgroud)

当您将 aFormGroup传入ControlValueAccessorComponent 时,作者正在使用FormGroup与传入对象相同的结构在组件内部初始化一个新的内部。那么直接传入FormGroup本身不是更好吗?或者封装提供了什么好处?

EDIT2:这是一个关于这个主题的有趣视频:

https://www.youtube.com/watch?v=CD_t3m2WMM8

小智 2

每当您使用本机 HTML 元素(输入、选择、按钮、表单等)时,请使用标准反应式表单 API

例如,当您必须使用自定义 HTML 元素(即 mat-list、mat-table、a​​g-grid-table 等)时,请使用 ControlValueAccessor,原因是它是一个充当Angular 表单 API 和 DOM 之间桥梁的接口元素。ControlValueAccessor 示例