首页 > 解决方案 > 将 `ngModelOptions` 从自定义组件传递到包含的本机元素

问题描述

我有一个ppo-currency-field使用以下模板调用的自定义组件(Angular 6):

<span class="display" tabindex="-1">{{formattedValue()}}</span>
<input #input class="input" type="number" [name]="name" 
    [tabindex]="tabindex" [readonly]="!!readonly || readonly===''" 
    [disabled]="!!disabled || disabled===''" [ngModel]="value" 
    (ngModelChange)="writeValue($event)" [ngModelOptions]="ngModelOptions">

我的组件代码包含以下行:

@Input() ngModelOptions: Object;

我正在使用我的组件:

<ppo-currency-field [ngModel]="data.planningHours.rate"
  (ngModelChange)="data.planningHours.rate = $event; recalc();"
  [ngModelOptions]="{ updateOn: 'blur' }" 
  [disabled]="!data.containsPlanning ? '' : null"></ppo-currency-field>

如您所见,我正试图ngModelOptions从我的自定义组件“传递”到input元素。但这不起作用,因为更新选项没有设置为“模糊”;事实上,似乎根本没有更新。

但是,当我直接input在元素上设置选项时,效果很好。

为什么我的传递不起作用,我该如何正确实施?

编辑:仅当我尝试ngModelOptions用作属性名称时才会出现问题。如果我将其更改为 eg options,它可以工作。我猜这没问题,但我试图让我的组件尽可能地表现得像本机输入字段。直觉上我不应该尝试重用 Angular 指令,但在这种情况下,ControlValueAccessor界面应该提供一个钩子来捕获这些选项,就像它对ngModel/所做的那样ngModelChange

标签: angular

解决方案


自定义组件级别的ngModelOptions属性适用于 ControlValueAccessor,而无需将内部输入元素绑定到自定义@Input() ngModelOptions属性,如您在此 stackblitz中所见。

为了ngModel使自定义组件的正确更新:

  1. 内部输入元素应在更改时更新(默认选项),以确保 ControlValueAccessor 也可以在更改时更新。

  2. 要使该{updateOn: 'blur'}选项起作用,onTouched应在输入元素失去焦点时调用 ControlValueAccessor 的事件回调:

<input ... 
  [ngModel]="value" 
  (ngModelChange)="writeValue($event)" 
  (blur)="onTouchedCallback()" />

onTouchedCallback自定义组件中设置的位置:

registerOnTouched(fn: any): void {
  this.onTouchedCallback = fn;
}

kara在Github上第 20384 期onTouched的评论中给出了需要调用回调的解释:

顶层的{updateOn: 'blur'}功能取决于它下面的控制值访问器是否registerOnTouched 正确实现。看起来您的自定义组件保存了回调,但从未真正调用它。由于它没有被调用,因此该值不会正确更新。我建议将 a 添加(blur)="onTouchedCallback()" 到您的 ControlValueAccessor 中,它应该可以工作。


推荐阅读