为什么在Angular中实现ControlValueAccessor时需要在writeValue中调用onChange和onTouch?
Why do I need call onChange and onTouch in writeValue when implementing ControlValueAccessor in Angular?
我已经实现了以下组件。它按预期工作和运行。然而,由于 ControlValueAccessor
的实现对我来说是新的,我不得不 follow a blog 不了解几个部分的更深层次的细节。所以这是一种“它有效但为什么?!”的情况。
@Component({ selector: ..., templateUrl: ..., styleUrls: ...,
providers: [{ provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputTextComponent),
multi: true }]
})
export class InputComponent implements ControlValueAccessor {
constructor() { }
@Input() info: string;
onChange: any = () => { }
onTouch: any = () => { }
writeValue(input: any): void {
this.info.value = input;
// this.onChange(input);
// this.onTouch();
}
registerOnChange(_: any): void { this.onChange = _; }
registerOnTouched(_: any): void { this.onTouch = _; }
setDisabledState?(state: boolean): void { }
onEdit(value: string): void { this.onChange(value); }
}
当我让它工作时,我注释掉了 writeValue(...)
方法的第二行和第三行,据我所知,没有任何问题。 other blogs 也一直建议这些调用,因此我确信省略它们是不合适的。但是,我不相信魔法,更喜欢做事有具体的理由。
为什么在 writeValue(...)
中执行对 onChange(...)
和 onTouch(...)
的调用很重要?会出现什么问题,在什么情况下会出现问题?
作为支线任务,我还尝试注释掉 the other methods,结果发现当我删除 setDisabledState(...)
时我无法说出任何事情。什么时候可以预期那个会引起问题?它真的需要实现吗(我见过括号前后都有问号的版本,参数如下:setDisabledState?(state: boolean): void { }
但也像这样:setDisabledState(state: boolean)?: void { }
)。
阅读这篇详细解释 ControlValueAccessor
的文章:
如果组件要用作 Angular 表单的一部分,通常需要在组件上实现 ControlValueAcceessor
接口。
I commented out the second and third line of writeValue(...) method
and, as far I can tell, nothing broke.
这可能是因为您没有应用任何表单指令 - formControl
或 ngModel
将 FormControl
链接到您的自定义输入组件。 FormControl
使用InputComponent
的writeValue
方法进行通信。
这是我在上面引用的文章中的图片:
writeValue
方法被 formControl
用来设置本机表单控件的值。 registerOnChange
方法被 formControl
用来注册一个预期在每次更新本机表单控件时触发的回调。 registerOnTouched
方法用于指示用户与控件交互。
Why is it important to execute the call to onChange(...) and
onTouch(...) in writeValue(...)? What will go wrong and under what
circumstances can it be expected?
这是实现 ControlValueAcceessor
的自定义控件通知 Angular 的 FormControl
输入中的值已更改或用户与控件交互的机制.
...discovered that I couldn't tell anything going bananas when I
removed setDisabledState(...)...Does it really need to be implemented?
如界面中所指定,当控件状态变为“禁用”或从“禁用”变为“禁用”时,此函数由表单 API 调用。根据值,它应该启用或禁用适当的 DOM 元素。
如果您想在关联的 FormControl
状态变为 disabled
时收到通知,然后您可以执行一些自定义逻辑(例如,禁用输入组件),则需要实现它。
我认为接受的答案没有以简洁的方式回答最核心的问题:
Why is it important to execute the call to onChange(...) and onTouch(...) in writeValue(...)?
不是。您 不需要 需要在 writeValue 中调用 onChange。这不是预期用途(请参阅下面的文档 link)。
What will go wrong and under what circumstances can it be expected?
预计不会出错。详细回答:
如果您是从内部writeValue
调用onChange
,您会注意到:
- 第一个 onChange 调用什么都不做。那是因为第一次调用writeValue时,onChange回调还没有被注册(即
registerOnChange
没有被调用)。
- 稍后从 writeValue 内部调用 onChange 会使用您从模型中给它的值(您刚刚收到的值)更新您的模型(使用
emitModelToViewChange = false
以避免递归调用 writeValue)。
换句话说,除非您依靠您的组件以某种方式立即更改它在 writeValue 中接收到的值,并将这些更改传递回您的模型,但 仅 second 和以后的 writeValue 调用,您可以安全地不从 writeValue 调用 onChange。
请参阅此处文档中的示例:https://angular.io/api/forms/ControlValueAccessor
我已经实现了以下组件。它按预期工作和运行。然而,由于 ControlValueAccessor
的实现对我来说是新的,我不得不 follow a blog 不了解几个部分的更深层次的细节。所以这是一种“它有效但为什么?!”的情况。
@Component({ selector: ..., templateUrl: ..., styleUrls: ...,
providers: [{ provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputTextComponent),
multi: true }]
})
export class InputComponent implements ControlValueAccessor {
constructor() { }
@Input() info: string;
onChange: any = () => { }
onTouch: any = () => { }
writeValue(input: any): void {
this.info.value = input;
// this.onChange(input);
// this.onTouch();
}
registerOnChange(_: any): void { this.onChange = _; }
registerOnTouched(_: any): void { this.onTouch = _; }
setDisabledState?(state: boolean): void { }
onEdit(value: string): void { this.onChange(value); }
}
当我让它工作时,我注释掉了 writeValue(...)
方法的第二行和第三行,据我所知,没有任何问题。 other blogs 也一直建议这些调用,因此我确信省略它们是不合适的。但是,我不相信魔法,更喜欢做事有具体的理由。
为什么在 writeValue(...)
中执行对 onChange(...)
和 onTouch(...)
的调用很重要?会出现什么问题,在什么情况下会出现问题?
作为支线任务,我还尝试注释掉 the other methods,结果发现当我删除 setDisabledState(...)
时我无法说出任何事情。什么时候可以预期那个会引起问题?它真的需要实现吗(我见过括号前后都有问号的版本,参数如下:setDisabledState?(state: boolean): void { }
但也像这样:setDisabledState(state: boolean)?: void { }
)。
阅读这篇详细解释 ControlValueAccessor
的文章:
如果组件要用作 Angular 表单的一部分,通常需要在组件上实现 ControlValueAcceessor
接口。
I commented out the second and third line of writeValue(...) method and, as far I can tell, nothing broke.
这可能是因为您没有应用任何表单指令 - formControl
或 ngModel
将 FormControl
链接到您的自定义输入组件。 FormControl
使用InputComponent
的writeValue
方法进行通信。
这是我在上面引用的文章中的图片:
writeValue
方法被 formControl
用来设置本机表单控件的值。 registerOnChange
方法被 formControl
用来注册一个预期在每次更新本机表单控件时触发的回调。 registerOnTouched
方法用于指示用户与控件交互。
Why is it important to execute the call to onChange(...) and onTouch(...) in writeValue(...)? What will go wrong and under what circumstances can it be expected?
这是实现 ControlValueAcceessor
的自定义控件通知 Angular 的 FormControl
输入中的值已更改或用户与控件交互的机制.
...discovered that I couldn't tell anything going bananas when I removed setDisabledState(...)...Does it really need to be implemented?
如界面中所指定,当控件状态变为“禁用”或从“禁用”变为“禁用”时,此函数由表单 API 调用。根据值,它应该启用或禁用适当的 DOM 元素。
如果您想在关联的 FormControl
状态变为 disabled
时收到通知,然后您可以执行一些自定义逻辑(例如,禁用输入组件),则需要实现它。
我认为接受的答案没有以简洁的方式回答最核心的问题:
Why is it important to execute the call to onChange(...) and onTouch(...) in writeValue(...)?
不是。您 不需要 需要在 writeValue 中调用 onChange。这不是预期用途(请参阅下面的文档 link)。
What will go wrong and under what circumstances can it be expected?
预计不会出错。详细回答:
如果您是从内部writeValue
调用onChange
,您会注意到:
- 第一个 onChange 调用什么都不做。那是因为第一次调用writeValue时,onChange回调还没有被注册(即
registerOnChange
没有被调用)。 - 稍后从 writeValue 内部调用 onChange 会使用您从模型中给它的值(您刚刚收到的值)更新您的模型(使用
emitModelToViewChange = false
以避免递归调用 writeValue)。
换句话说,除非您依靠您的组件以某种方式立即更改它在 writeValue 中接收到的值,并将这些更改传递回您的模型,但 仅 second 和以后的 writeValue 调用,您可以安全地不从 writeValue 调用 onChange。
请参阅此处文档中的示例:https://angular.io/api/forms/ControlValueAccessor