I would like to build on the answer given by @omeralper , which in my opinion provided a good foundation for a solid solution.
What I am proposing is a simplified and up to date version with the latest web standards. It is important to note that event.keycode is removed from the web standards, and future browser updates might not support it anymore. See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
Furthermore, the method
String.fromCharCode(e.keyCode);
does not guarantee that the keyCode pertaining to the key being pressed by the user maps to the expected letter as identified on the user's keyboard, since different keyboard configurations will result in a particular keycode different characters. Using this will introduce bugs which are difficult to identify, and can easily break the functionality for certain users. Rather I'm proposing the use of event.key, see docs here https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
Furthermore, we only want that the resultant output is a valid decimal. This means that the numbers 1, 11.2, 5000.2341234 should be accepted, but the value 1.1.2 should not be accepted.
Note that in my solution i'm excluding cut, copy and paste functionality since it open windows for bugs, especially when people paste unwanted text in associated fields. That would required a cleanup process on a keyup handler; which isn't the scope of this thread.
Here is the solution i'm proposing.
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[myNumberOnly]'
})
export class NumberOnlyDirective {
// Allow decimal numbers. The \. is only allowed once to occur
private regex: RegExp = new RegExp(/^[0-9]+(\.[0-9]*){0,1}$/g);
// Allow key codes for special events. Reflect :
// Backspace, tab, end, home
private specialKeys: Array<string> = [ 'Backspace', 'Tab', 'End', 'Home' ];
constructor(private el: ElementRef) {
}
@HostListener('keydown', [ '$event' ])
onKeyDown(event: KeyboardEvent) {
// Allow Backspace, tab, end, and home keys
if (this.specialKeys.indexOf(event.key) !== -1) {
return;
}
// Do not use event.keycode this is deprecated.
// See: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
let current: string = this.el.nativeElement.value;
// We need this because the current value on the DOM element
// is not yet updated with the value from this event
let next: string = current.concat(event.key);
if (next && !String(next).match(this.regex)) {
event.preventDefault();
}
}
}