Angular使用带有@HostListener的指令来更新ReactiveForm的输入值是将输入设置为ngValid而不是ngInvalid

mtp*_*ltz 4 angular-directive angular

我已经在输入事件(onKeyDown)上ReactiveForm FormControl使用了一个货币属性指令@HostListener来删除所有无效字符(字母和符号),因为它们被输入到输入中,但允许数字和小数.但是,如果a在空输入字段中键入无效字符(即.)并且指令将其删除,则不会更新模型.

我使用货币指令添加了一个plunker设置.要了解我的问题,请遵循以下步骤:

  1. 键入123a你没有a在输入中输入,因为不允许使用字母,并且由于表单无效而按钮被禁用(好)
  2. 键入123.456你没有6在输入中输入,因为只允许2个小数位,并且由于表单无效而按钮被禁用(好)
  3. 类型a你没有a在输入中获得,但是对接是启用的,因为模型认为它有一个ain,即使UI没有显示它(坏)

您可以通过单击按钮并查看控制台,日志this.form.value和显示来验证模型是否未更新{ amount: 'a' }.如果您接下来键入一个有效字符,模型将只包含该字符,并且a将被删除.因此,只有在这种情况下,模型才能正确更新.

这是在使用AngularJS容易解决的问题ngModel validator and parser pipes,对modelValue,$setViewValue以及$render()更新和力AngularJS运行$摘要.你是怎么做Angular的?

这是我的属性指令的片段,它成功地删除了不需要的字符:

@HostListener('input', ['$event'])
  onKeyDown(event: KeyboardEvent) {
    const input = event.target as HTMLInputElement;

    // Only numbers and decimals
    let trimmed = input.value.replace(/[^\d\.,]+/g, '');

    // Only a single decimal and choose the first one found
    if (trimmed.split('.').length > 2) {
      trimmed = trimmed.replace(/\.([^\.]*)$/, '$1');
    }

    // Cannot start with decimal typed or pasted
    if (trimmed.indexOf('.') === 0) { trimmed = ''; }

    // AngularJS "like" solution would be something like:
    // ngModelCtrl.$setViewValue(trimmed);
    // ngModelCtrl.$render();
    // Angular solution is???

    input.value = trimmed;
}
Run Code Online (Sandbox Code Playgroud)

mtp*_*ltz 9

所以我确实找到了一个解决方案,使用NgControl我注入的地方private ngControl: NgControl然后访问它的控件属性this.ngControl.control.patchValue(newValue);,ReactiveForm在我的onKeyDown事件中更新输入字段模型- 请参阅plunker

但是基于智能和哑组件的使用,使用EventEmittera实际上是一个更好的解决方案,将值从输入 - plunker传递给父表单(感谢Todd Motto和他的Ultimate Angular课程)