Skip to content

Instantly share code, notes, and snippets.

@ahmeti
Last active May 7, 2024 14:54
Show Gist options
  • Save ahmeti/5ca97ec41f6a48ef699ee6606560d1f7 to your computer and use it in GitHub Desktop.
Save ahmeti/5ca97ec41f6a48ef699ee6606560d1f7 to your computer and use it in GitHub Desktop.
Angular 5 - Only Number Input, Only Number Decimal

Angular 5,6,7,8,9 - Only Number Input, Only Decimal Input

v1 Online Demo: https://codesandbox.io/s/v1-angular-numeric-ljwlb

v1 Gist : https://gist.github.com/ahmeti/5ca97ec41f6a48ef699ee6606560d1f7/e36956cc355ad1bad6898e9eede5d7a9219947e8

v2 Online Demo: https://codesandbox.io/s/v2-angular-numeric-3w2wr

Allow Only Numbers (Without Decimal)

<input numeric type="text">

Allow Numbers & Only Two Decimals [0-9] (With Decimal Limit)

<input numeric decimals="2" type="text">
// Version 2

import {
    Directive,
    ElementRef,
    HostListener,
    Input
} from "@angular/core";

@Directive({
    selector: "[numeric]"
})
export class NumericDirective {
    @Input("decimals") decimals: int = 0;

    private check(value: string) {
        if (this.decimals <= 0) {
            return String(value).match(new RegExp(/^\d+$/));
        } else {
            var regExpString =
                "^\\s*((\\d+(\\.\\d{0," +
                this.decimals +
                "})?)|((\\d*(\\.\\d{1," +
                this.decimals +
                "}))))\\s*$";
            return String(value).match(new RegExp(regExpString));
        }
    }

    private run(oldValue) {
        setTimeout(() => {
            let currentValue: string = this.el.nativeElement.value;
            if (currentValue !== '' && !this.check(currentValue)) {
                this.el.nativeElement.value = oldValue;
            }
        });
    }

    constructor(private el: ElementRef) {}

    @HostListener("keydown", ["$event"])
    onKeyDown(event: KeyboardEvent) {
        this.run(this.el.nativeElement.value);
    }

    @HostListener("paste", ["$event"])
    onPaste(event: ClipboardEvent) {
        this.run(this.el.nativeElement.value);
    }

}
@lujian98
Copy link

To access ngControl, add @Optional() @Self() private ngControl: NgControl, to constructor:

 constructor(
    @Optional() @Self() private ngControl: NgControl,
    private el: ElementRef<HTMLInputElement | HTMLTextAreaElement>,
  ) { }

    if (this.ngControl) {
      this.ngControl.control.patchValue(oldValue, { emitEvent: false, onlySelf: true });
    }

@LSzelecsenyi
Copy link

LSzelecsenyi commented Dec 2, 2022

Thank you, very useful!
As @rbrijesh mentioned, if one types more than the maximum decimals, the input does not show it, but the value of the input is longer by one number. Is there a fix for this? I could not find what causes it.

@LSzelecsenyi
Copy link

Here is a fixed version. It uses NgControl.valueChanges insted of @HostListeners which fixes the extra character at the end of the input when submitting the form.

`

import { Directive, Input, OnInit } from '@angular/core';
import { NgControl } from '@angular/forms';
import { distinctUntilChanged, pairwise, Subscription } from 'rxjs';

@Directive({
    selector: '[restrictedDecimals]'
})
export class InstrumentDecimalsDirective implements OnInit {
    @Input() decimals = 0;
    @Input() negative = 0;
    @Input() separator = ',';
    valueSubscription: Subscription;

    constructor(public ngControl: NgControl) {}

    ngOnInit(): void {
        this.ngControl.valueChanges.pipe(distinctUntilChanged(), pairwise()).subscribe(([oldValue, newValue]) => {
            this.runCheck(oldValue, newValue);
        });
    }

    private runCheck(oldValue, newValue) {
        const allowNegative = this.negative > 0 ? true : false;

        if (allowNegative) {
            if (!['', '-'].includes(newValue) && !this.checkAllowNegative(newValue)) {
                this.ngControl.control.setValue(oldValue);
            }
        } else {
            if (newValue !== '' && !this.check(newValue)) {
                this.ngControl.control.setValue(oldValue);
            }
        }
    }

    private checkAllowNegative(value: string) {
        if (this.decimals <= 0) {
            return new RegExp(/^-?\d+$/).exec(String(value));
        } else {
            const regExpString =
                '^-?\\s*((\\d+(\\' + this.separator + '\\d{0,' + this.decimals + '})?)|((\\d*(\\' + this.separator + '\\d{1,' + this.decimals + '}))))\\s*$';
            return new RegExp(regExpString).exec(String(value));
        }
    }

    private check(value: string) {
        if (this.decimals <= 0) {
            return new RegExp(/^\d+$/).exec(String(value));
        } else {
            const regExpString =
                '^\\s*((\\d+(\\' + this.separator + '\\d{0,' + this.decimals + '})?)|((\\d*(\\' + this.separator + '\\d{1,' + this.decimals + '}))))\\s*$';
            return new RegExp(regExpString).exec(String(value));
        }
    }
}

`

@akshaywadatkar
Copy link

is there any new update for 13

@LSzelecsenyi
Copy link

is there any new update for 13

it works with angular v14

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment