Home > OS >  Angular directive to restrict decimals after coma
Angular directive to restrict decimals after coma

Time:12-16

My goal is to create a directive which allows to set the number of decimals in an input field. (also make it possible to change the decimal separator, but it is irrelevant now) It seems to work, I am not able to enter more numbers into the input field than it is specified, but when submitting the form the value is longer by one character. Here's the code:


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

@Directive({
    selector: '[restrictedDecimals]'
})
export class InstrumentDecimalsDirective {
    @Input() decimals = 0;
    @Input() separator = '.';
    private readonly check = new RegExp(/^\d $/);

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

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

    constructor(private readonly el: ElementRef) {}

    @HostListener('keydown', ['$event'])
    onKeyDown(event: KeyboardEvent) {
        const oldValue = this.el.nativeElement.value;
        this.run(oldValue);

        const currentValue: string = this.el.nativeElement.value;
        if (currentValue !== '' && !this.check(currentValue)) {
            event.preventDefault();
        }
    }
}

CodePudding user response:

Solved it:

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