Angular 控值訪問器(Control Value Accessor)
一个 ControlValueAccessor 工具是什么?
你知道 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();
}
}
结论部分
- ControlValueAccessor 是一个接口,Angular 组件可以通过实现该接口来绑定到表单控件;
- 它就像一个桥梁,连接 Angular 表单 API 和自定义组件;
- 表单控件的值和你自己的组件状态应该保持同步,并且在发生变化时相互更新,无论是通过外部的 writeValue() 调用还是内部的 onChange() 调用来更新状态。
- 特别感谢 Kayzhe Tsar 的审阅。
感谢你加入_简单英语_社区!在你离开之前,还有点事想说:
- 记得给作者点赞并关注他/她 ️👏👏️️
- 关注我们: X | LinkedIn | YouTube | Discord | Newsletter
- 看来看我们其他平台: CoFeed | Differ
- 更多内容请在 PlainEnglish.io 查看
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦