2 回答
TA贡献2039条经验 获得超7个赞
控制值存取器 (CVA)
该ControlValueAccessor界面是你在找什么。
为什么?该接口将 DOM 与 Angular Form 分离,允许显示下拉和输入与表单实际使用的值不同。
您可以将自定义输入实现为单独的组件*并传入 FormControl。
以下是未经测试的工作 Stackblitz
*编辑 3 - 我相信也可以将其作为指令来实现。请参阅 - 实现 ControlValueAccessor 的 Angular 2 指令不会在更改时更新“已触摸”属性
黑匣子外
你的app.component.html最终看起来像。
<form class="example-form">
<app-auto-special [users]="options" [formControl]="myControl"></app-auto-special>
</form>
app-auto-special就像一个黑匣子,它只关心用户 ID。
我们可以 patchValue 或 setValue ,它会做它的事情(在内部调用writeValue)。如果我们与该组件交互,我们将获得 FormControl 值的用户 ID。
编辑- 没有什么能阻止你传递整个 User 对象。我假设 OP 基于这个问题想要 id。
编辑 2 - 传递用户对象而不是工作 Stackbliz 的示例
黑匣子里面
我们需要使用 NG_VALUE_ACCESSOR将app-auto-special组件注册为 controlValueAccessor 的提供者。这是通过以下方式完成的:
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AutoSpecialComponent),
multi: true
}]
所以在黑盒子里我们实现了由 4 个方法组成的接口:
writeValue(obj: any): void
registerOnChange(fn: any): void
registerOnTouched(fn: any): void
setDisabledState(isDisabled: boolean)?: void
这通常意味着以下样板:
export class AutoSpecialComponent implements ControlValueAccessor {
public _value: number;
public disabled: boolean;
onChanged: any = () => {};
onTouched: any = () => {};
/*
* ControlValueAccessor boilerplate
*
*/
writeValue(value): void {
this._value = value
}
registerOnChange(fn: any): void {
this.onChanged = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled
}
}
我们制作了registerOnChangeand提供的函数的副本,并在我们想要更新 formControl 值或它在 touch 属性上时registerOnTouched调用这些副本(this.onChanged和this.onTouched)。setDisabledState是可选的,writeValue在初始化时或当我们从父级调用patchValue或时调用setValue。
要设置我们调用的 FormControl this.onChanged(some_value);,我们可以挂钩各种事件input, focusin, blur,optionSelected并决定分别发生什么:
表单控件值
显示哪些选项
输入中应该是什么显示字符串
这个答案附带了一个警告,即这是我完成的第一个 CVA 实现之一,所以我在基础上摇摇欲坠。
额外的好处
单元测试 - 独立的 DOM 显示与表单
逻辑分离——父级不再饱和
添加回答
举报