angularinputangular-directiveangular19mat-input

Angular: Numbers only directive


I have this piece of code

  <input matInput type="number" [(ngModel)]="value"
  (ngModelChange)="onChange(true)" />

But I want to be able to enter only numbers, not other characters like + , . -

I found this directive https://stackblitz.com/edit/angular-numbers-only-directive?file=app%2Fapp.component.ts

The problem is that the onChange method is called even if I enter an invalid value. I don't want to put the same condition in the onChange method; I want to be able to modify the directive to emit the event or not. So it should only work if it's actually a number. I found some solutions with keyPress, but it is deprecated. I am using angular 19


Solution

  • I found a solution that seems to work. It handles both the cursor and the event emit.

    <input matInput numbersOnly [(ngModel)]="value"
        (ngModelChange)="onChange(true)" />
    

    Directive

    import {Directive, HostListener} from "@angular/core";
    
    @Directive({
        selector: '[numbersOnly]',
    })
    export class NumbersOnlyDirective {
        private readonly regExpr = new RegExp('^([1-9]\\d*|0)$');
    
        constructor() {
        }
    
        @HostListener('beforeinput', ['$event'])
        onBeforeInput(event: InputEvent) {
            if (!event.data) {
                return;
            }
    
            const input = event.target as HTMLInputElement;
    
            const currentVal = input.value;
            const start = input.selectionStart || 0;
            const end = input.selectionEnd || 0;
    
            const nextVal =
                currentVal.substring(0, start) + event.data + currentVal.substring(end);
    
            if (!this.regExpr.test(nextVal)) {
                event.preventDefault();
            }
        }
    }