Passing `ngModelOptions` through from a custom component to a contained native element

偶尔善良 提交于 2021-02-10 18:47:37

问题


I have a custom component (Angular 6) called ppo-currency-field with the following template:

<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">

My component code contains the line:

@Input() ngModelOptions: Object;

I'm using my component with:

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

As you can see, I'm attempting to "pass through" the ngModelOptions from my custom component to the input element. But this doesn't work, because the update option is not being set to "blur"; in fact, no update seems to be happening at all anymore.

However, when I set the option on the input element directly, that works perfectly.

Why doesn't my pass-through work, and how could I implement it properly?

EDIT: the problem only occurs when I try to use ngModelOptions as the attribute name. If I change it to e.g. options, it works. This is ok I guess, but I was attempting to make my component behave as much as a native input field as possible. It makes intuitive sense that I shouldn't try to reuse an Angular directive, but in that case the ControlValueAccessor interface should offer a hook to catch these options, as it does for ngModel/ngModelChange.


回答1:


The ngModelOptions property at the custom component level applies to the ControlValueAccessor without having to bind the inner input element to a custom @Input() ngModelOptions property, as you can see in this stackblitz.

In order for the ngModel of the custom component to update correctly:

  1. The inner input element should update on change (the default option), to make sure that the ControlValueAccessor can also update on change.

  2. For the {updateOn: 'blur'} option to work, the onTouched event callback of the ControlValueAccessor should be called when the input element loses focus:

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

where onTouchedCallback is set in the custom component:

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

The explanation for the need to call the onTouched callback is given in a comment by kara in issue 20384 on Github:

The {updateOn: 'blur'} functionality on the top level depends on the control value accessor underneath it implementing registerOnTouched properly. It looks like your custom component saves the callback, but never actually calls it. Since it's not called, the value doesn't update properly. I'd recommend adding a (blur)="onTouchedCallback()" to your ControlValueAccessor and it should work.



来源:https://stackoverflow.com/questions/53935844/passing-ngmodeloptions-through-from-a-custom-component-to-a-contained-native-e

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!