从自定义组件传递ngModelOptions到包含的本机元素

时间:2018-12-26 18:41:17

标签: angular

我有一个名为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元素。但这是行不通的,因为未将update选项设置为“ blur”;实际上,似乎根本没有更新。

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

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

编辑:仅当我尝试使用ngModelOptions作为属性名称时,才会出现此问题。如果我将其更改为例如options,它可以工作。我猜这没关系,但是我试图使我的组件表现得尽可能多的本机输入字段。从直觉上讲,我不应该尝试重用Angular指令,但是在那种情况下,ControlValueAccessor接口应该提供一个钩子来捕获这些选项,就像ngModel / {{1} }。

1 个答案:

答案 0 :(得分:2)

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

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

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

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

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

在自定义组件中设置了onTouchedCallback的地方:

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

在Github上,kara中的issue 20384在注释中给出了需要调用onTouched回调的说明:

  

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