你知道 ControlValueAccessor 工具是什么吗?
控制值访问器接口(注释:ControlValueAccessor)是一个可以由你的组件实现的接口,使该组件能够像表单控件一样工作。
这意味着您可以像绑定 <input>
元素一样,将表单控件绑定到您的组件。
<form [formGroup]="formGroup"> <your-cool-component [control]="formControl1" /> <input [control]="formControl2"> </form>
这是通过正确实现YourAwesomeComponent
类中的ControlValueAccessor
接口才实现的。上面的例子展示了反应式表单,同样的道理也适用于模板驱动表单。
在我撰写这段文字的时候,Angular 的文档目前还没有很清晰地说明如何在一个实际案例中使用_ControlValueAccessor_
接口。每次我需要实现这个接口时,我都需要从网上找到的相关示例中重新理解它的构建模块的意义。这就是我在这里分享我的笔记的原因,希望帮助未来的自己和其他可能遇到同样问题的开发者们。
网上有许多教程通过实际案例展示如何使用ControlValueAccessor接口,并让用户自己理解接口各部分的含义。
我想在这里采用相反的做法:下面是一个模拟实现该接口的组件的例子,每个构建块都在注释中做了说明。
import { Component, Optional, Self } from '@angular/core'; import { ControlValueAccessor, NgControl } from '@angular/forms'; @Component({ selector: 'your-awesome-component', templateUrl: './your-awesome.component.html', }) export class YourAwesomeComponent implements ControlValueAccessor { // 自定义:你的组件将拥有某种内部状态。 // 你决定它的类型以及它是如何运作的, // 根据你的使用情况。 // 也可能不止一个字段,这完全取决于 // 你的具体情形。 protected internalComponentState; // 控制:如果你需要跟踪绑定控制的禁用状态 protected disabled = false; // 这些是占位函数(实际的函数将由 // 消费者设置 - 请参见下面的 registerOn* 方法)。 // 我们需要在每次进行更改时都调用它们, // 这些更改必须反映给该组件的外部消费者, // 以指示表单控件何时被触摸 // 和/或其值何时被更改。 onChange: (value: string) => unknown = (_value: string) => {}; onTouched: () => unknown = () => {}; // 如果你需要从组件内部访问 FormControl 控制 // 它将存在于 this.ngControl.control constructor(@Optional() @Self() public ngControl: NgControl) { if (this.ngControl) { this.ngControl.valueAccessor = this; } } // 允许消费者注册一个 onChange 函数 registerOnChange(fn: (value: string) => unknown): void { // 通常这里就是这样,无需更改任何内容 this.onChange = fn; } // 允许消费者注册一个 onTouched 函数 registerOnTouched(fn: () => unknown): void { // 通常这里就是这样,无需更改任何内容 this.onTouched = fn; } // 这是可选的, // 它允许你对表单控件的禁用状态作出反应 setDisabledState(isDisabled: boolean): void { // 我们将新的禁用状态绑定到 // 内部(自定义)"disabled" 字段 // 这是你通常要用这个函数做的事情 // 但不是强制性的 this.disabled = isDisabled; } // 每当表单控件的值发生变化时都会调用此方法 writeValue(newValue: string): void { // 你希望对 newValue 所做的取决于你的使用情况 // 通常你想将它映射到你的 internalComponentState // 例如: this.internalComponentState = someProcessingFunction(newValue); // 注意: 你可能希望只在 newValue 与 // 当前的内部组件状态有所不同的情况下执行任何操作, // 以便优化性能 } // 自定义:从内部处理组件状态的变化 onWhenTheUserPerformedSomeAction(): void { // 在某个时刻,你想处理组件状态的变化 // 并将它们反映到外部(与 this.writeValue() 相反) // 例如: 你的状态发生了变化 this.internalComponentState = /*在这里做一些更改*/ const newValue = someMappingFunction(this.internalComponentState); // 现在你想发出这些变化并更新表单的值: this.onChange(newValue); // 这可能意味着你的表单控件现在也应该被视为已“被触碰”了。 this.onTouched(); } }
感谢你加入_简单英语_社区!在你离开之前,还有点事想说: