1

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

2 Answers 2

0

Ideally you should just set type="number" to block non numeric characters.

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

In your code, you can just add an EventEmitter which fires only when a valid value is present.

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

@Directive({
  selector: 'input[numbersOnly]',
})
export class NumberDirective {
  @Output() valueChange = new EventEmitter();
  constructor(private _el: ElementRef) {}

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

Stackblitz Demo

Sign up to request clarification or add additional context in comments.

1 Comment

Please, check the position of the cursor when change, see, e.g. this SO, and it's important check if is applied to a NgModel or FormControl
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.