在Angular中实现ControlValueAccessor时,为什么需要在writeValue中调用onChange和onTouch?

在Angular中实现ControlValueAccessor时,为什么需要在writeValue中调用onChange和onTouch?,angular,typescript,custom-component,Angular,Typescript,Custom Component,我已经实现了以下组件。它的工作和行为符合预期。然而,由于ControlValueAccessor的实现对我来说是新的,因此我不得不在不了解几个部分的更深层细节的情况下进行修改。所以这是一种“它有效,但为什么?!”的情况 @Component({ selector: ..., templateUrl: ..., styleUrls: ..., providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forw

我已经实现了以下组件。它的工作和行为符合预期。然而,由于
ControlValueAccessor
的实现对我来说是新的,因此我不得不在不了解几个部分的更深层细节的情况下进行修改。所以这是一种“它有效,但为什么?!”的情况

@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(…)
方法的第二行和第三行,据我所知,没有任何东西坏掉。这些电话也一直是由建议的,所以我相信省略它们是不合适的。然而,我不相信魔法,我更喜欢有一个具体的理由去做事情

为什么在
writeValue(…)
中执行对
onChange(…)
onTouch(…)
的调用很重要?什么会出错?在什么情况下可以预期


作为一项附带任务,我还尝试注释掉,发现当我删除
setDisabledState(…)
时,我看不出有什么事情变得疯狂。什么时候会出现问题?它真的需要实现吗(我见过在括号前后都带有问号的版本,参数如下:
setDisabledState?(状态:boolean):void{}
,但也像这样:
setDisabledState(状态:boolean)?:void{}
).

阅读这篇文章,详细解释
ControlValueAccessor

如果组件被用作角形的一部分,通常需要在组件上实现
ControlValueAcceessor
接口

我注释掉了writeValue(…)方法的第二行和第三行 而且,据我所知,什么也没破

这可能是因为您没有应用任何将
formControl
链接到自定义输入组件的表单指令-
formControl
ngModel
FormControl
使用
InputComponent
writeValue
方法进行通信

下面是我上面提到的文章中的图片:

formControl
使用
writeValue
方法将值设置为本机表单控件。
formControl
使用
registerChange
方法注册回调,该回调预计在每次更新本机表单控件时都会触发。
方法用于指示用户与控件交互

为什么执行对onChange(…)的调用和 onTouch(…)的书面值(…)?什么会出错,在什么情况下 情况如何

这是实现
ControlValueAcceessor
的自定义控件通知Angular的
FormControl
输入中的值已更改或用户与控件交互的机制

…发现当我离开时我什么都说不出来 删除了setDisabledState(…)…是否真的需要实现它

如接口中所指定,当控件状态更改为“禁用”或从“禁用”更改为“禁用”时,forms API将调用此函数。根据该值,它应该启用或禁用相应的DOM元素。
如果您希望在关联的
FormControl
的状态变为
disabled
时收到通知,然后您可以执行一些自定义逻辑(例如,禁用您的输入组件),则需要实现它。

我不认为公认的答案以简洁的方式回答了最核心的问题:

为什么在writeValue(…)中执行对onChange(…)和onTouch(…)的调用很重要

事实并非如此。您不需要在writeValue中调用onChange。它不是预期用途(请参阅下面的文档链接)

什么会出错?在什么情况下可以预期

别指望出什么差错。详细回答:

如果要从内部调用
onChange
,您会注意到:

  • 第一个onChange调用什么都不做。这是因为在首次调用writeValue时,onChange回调尚未注册(即未调用registerChange
  • 稍后从writeValue内部对onChange的调用将使用您从模型中提供的值(您刚刚收到的值)更新您的模型(使用
    emitModelToViewChange=false
    以避免递归调用writeValue)
  • 换句话说,除非您依靠组件以某种方式立即更改它在writeValue中接收到的值,并让它将这些更改传递回您的模型,但仅在第二次或以后调用writeValue时,否则您不必从writeValue调用onChange


    请参阅此处文档中的示例:

    您如何使用此组件?您是否阅读了?
    为什么在writeValue(…)中执行对onChange(…)和onTouch(…)的调用很重要
    你在哪里看到的?@yurzui,这里可能指的是@angolarindepth.com,我认为他指的是这个伟大的答案。不过有两次跟进#1如果我已经注册了
    onChange()
    ,但没有从
    writeValue()
    调用它(只将值设置为backing字段,而没有将其传播到
    onChange()
    ),我仍然会将值获取到父组件中的表单组。那么现在什么不起作用了?我看不见。你有没有一个明确的例子来说明什么是不可行的#2我见过
    setDisableState()
    没有问号,方法名称后面有问号,括号后面有问号。这是相同的意思吗?这是怎么回事?@Donkeybana,请阅读我引用的文章,如果你在那之后仍然有问题,请创建一个stackblitz演示,并让我知道文章中有什么不清楚的地方,你必须调用
    onChange