Input field accepting only numbers without firing events when input other caracters

余生长醉 提交于 2019-12-05 09:31:02

问题


I'm not satisfied with the default behavior of the html number input, I would like to have a simple input that accepts only numbers.

I created this directive :

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();
    }
  }

}

The issue I'm facing is that the "event.stopPropagation()" does not stop the event propagation, an event is fired even if the input value does not change from the user point of view.

How can I stop the event propagation when the field value has not changed ?

Edit : For better understanding, here is a stackblitz example : https://stackblitz.com/edit/angular-numbers-only-directive


回答1:


I don't really think there is a way to stop this event using directive with HostListener.

Angular detected this event before you listener was called so stopping propagation will not affect Angular events like ngModelChange to which you react in parent component. (no proof for that so I may be wrong)

I would suggest to provide own event indicating value change and emit it when you really want it to be emitted:

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);
    }
  }

}

Then you can replace ngModelChanged binding with numberChanged:

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

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




回答2:


For usage in reactive forms, I ended up making a custom component implementing ControlValueAccessor :

The component declaration (extract) :

@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);
    }
  }

  ...
}

Usage :

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

Here is the stackblitz.



来源:https://stackoverflow.com/questions/47555587/input-field-accepting-only-numbers-without-firing-events-when-input-other-caract

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