当输入其他字符时,输入字段仅接受数字而不触发事件

时间:2017-11-29 14:51:27

标签: angular typescript angular-directive

我对html数字输入的默认行为不满意,我想要一个只接受数字的简单输入。

我创建了这个指令:

import { Directive, ElementRef, HostListener, Input } from '@angular/core';
import { NgControl } from '@angular/forms';

@Directive({
  selector: 'input[numbersOnly]'
})
export class NumberDirective {

  constructor(private _el: ElementRef) { }

  @HostListener('input', ['$event']) onInputChange(event) {
    const initalValue = this._el.nativeElement.value;
    this._el.nativeElement.value = initalValue.replace(/[^0-9]*/g, '');
    if ( initalValue !== this._el.nativeElement.value) {
      event.stopPropagation();
    }
  }

}

我面临的问题是“event.stopPropagation()”不会停止事件传播,即使输入值没有从用户的角度改变,也会触发事件。

如果字段值未更改,如何停止事件传播?

编辑: 为了更好地理解,这里是一个stackblitz示例: https://stackblitz.com/edit/angular-numbers-only-directive

2 个答案:

答案 0 :(得分:1)

我真的认为有一种方法可以使用HostListener指令停止此事件。

Angular在调用侦听器之前检测到此事件,因此停止传播不会影响您在父组件中作出反应的ngModelChange之类的Angular事件。(没有证据证明我可能是错)

我建议提供指示值更改的自己的事件,并在您真正希望它发出时发出它:

export class NumberDirective {
  @Output() numberChanged = new EventEmitter<number>();

  constructor(private _el: ElementRef) { }

  @HostListener('input', ['$event']) onInputChange(event) {
    const initalValue = this._el.nativeElement.value;
    this._el.nativeElement.value = initalValue.replace(/[^0-9]*/g, '');
    if ( initalValue === this._el.nativeElement.value) {
      this.numberChanged.emit(initalValue);
    }
  }

}

然后,您可以将ngModelChanged绑定替换为numberChanged

<input type="text" [ngModel]="value" (numberChanged)="onChange($event)" numbersOnly/>

演示: https://stackblitz.com/edit/angular-numbers-only-directive-a2mv6e

答案 1 :(得分:0)

为了在反应形式中使用,我最终制作了一个实现ControlValueAccessor的自定义组件:

组件声明(摘录):

@Component({
  selector: 'number',
  template: `
    <input type="text" [(ngModel)]="value" numbersOnly/>
  `,
  ...
  ]
})
export class NumberInputComponent implements ControlValueAccessor {
  ...

  set value(value) {
    const tmp = value.replace(/[^0-9]*/g, '');
    if(tmp && tmp !== '' && +tmp !== +this._value) {
      this._value = +tmp;
      this.onChange(this._value);
    }
  }

  ...
}

用法:

<number [formControl]="formControl"></number>

Here is the stackblitz.