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

Don*_*ana 6 custom-component typescript angular

我已经实现了以下组件.它的工作和行为符合预期.然而,由于实施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); }
}
Run Code Online (Sandbox Code Playgroud)

当我开始工作的时候,我评论了方法的第二和第三行writeValue(...),而且据我所知,没有任何事情发生.其他博客也一直建议这些电话,所以我确信省略它们是不恰当的.但是,我不相信魔法,宁愿有一个具体的理由去做事.

为什么是重要的执行调用onChange(...)onTouch(...)writeValue(...)?会出现什么问题,在什么情况下可以预料到?

作为一个副作用,我也尝试评论其他方法,并发现当我移除时我无法告诉任何香蕉setDisabledState(...).什么时候可以预期会导致问题?它是否真的需要实现(我已经在括号前后看到带有问号的版本,参数如此:setDisabledState?(state: boolean): void { }但也像这样:)setDisabledState(state: boolean)?: void { }.

Max*_*kyi 10

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

如果ControlValueAcceessor组件应该用作Angular表单的一部分,通常需要在组件上实现接口.

我注释掉了writeValue(...)方法的第二行和第三行,据我所知,没有任何内容破坏.

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

以下是我在上面引用的文章中的图片:

在此输入图像描述

writeValue方法用于formControl将值设置为本机表单控件.该registerOnChange方法用于formControl注册每次更新本机表单控件时预期触发的回调.该registerOnTouched方法用于指示用户与控件交互.

为什么在writeValue(...)中执行对onChange(...)和onTouch(...)的调用很重要?会出现什么问题,在什么情况下可以预料到?

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

...发现当我删除setDisabledState(...)时我无法告诉任何香蕉...它真的需要实现吗?

如界面中所指定,当控件状态更改为"DISABLED"或从"DISABLED"更改时,此函数由表单API调用.根据值,它应启用或禁用适当的DOM元素.如果希望在关联状态FormControl变为通知时收到通知,则需要实现它disabled,然后可以执行某些自定义逻辑(例如,禁用输入组件).

  • 如果用户与您的 DOM 控件交互并更改其值,您必须调用 `onChange`,以便将该值写入表单值。在 `writeValue` 中调用它是错误的。如果程序更改了表单控件的值,表单将调用此函数。您只需更新 DOM 控件以反映当前的表单值。 (4认同)

cor*_*lla 6

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

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

不是。你不会需要调用的onChange在writeValue。这不是预期用途(请参阅下面的文档链接)。

会出现什么问题,在什么情况下可以预期?

期待不会出错。详细回答:

如果你调用onChange来自内部writeValue,你会发现:

  • 第一个 onChange 调用什么都不做。那是因为registerOnChange当首次调用 writeValue 时,onChange 回调尚未注册(即未调用)。
  • 稍后从 writeValue 内部调用 onChange 更新您的模型(emitModelToViewChange = false以避免递归调用 writeValue),使用您给它的值 - 您刚刚收到 - 从您的模型。

换句话说,除非您依靠您的组件以某种方式立即更改它在 writeValue 中接收到的值,并且为了将这些更改传递回您的模型,但第二次和以后的 writeValue 调用时,您可以安全地不调用 onChange从写值。

请参阅此处文档中的示例:https : //angular.io/api/forms/ControlValueAccessor