Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Directive to limit decimal numbers to 100.00 max in text input (Regex)

I have a directive, which is limit text input to write only decimal numbers in the text input

Here is code of directive

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

@Directive({
    exportAs: 'decimal-number-directive',
    selector: 'decimal-number-directive, [decimal-number-directive]',
})
export class DecimalNumberDirective {
    private regex: RegExp = new RegExp(/^\d*\.?\d{0,2}$/g);
    private specialKeys: string[] = ['Backspace', 'Tab', 'End', 'Home'];
    constructor(private el: ElementRef) {}
    @HostListener('keydown', ['$event'])
    onKeyDown(event: KeyboardEvent): void {
        if (this.specialKeys.indexOf(event.key) !== -1) {
            return;
        }

        const current: string = this.el.nativeElement.value;
        const next: string = current.concat(event.key);
        if (next && !String(next).match(this.regex)) {
            event.preventDefault();
        }
    }
}

Here is input where I use it

<div class="col-2 pr-0">
                        <label>{{ l('Percent') }}</label>
                        <input
                            class="form-control"
                            type="text"
                            decimal-number-directive
                            name="percent"
                            [(ngModel)]="inquiryItemToAdd.percent"
                            maxlength="64"
                            (ngModelChange)="setTotalPrice()"
                            [readOnly]="!inquiryItemToAdd.servicePriceId || !servicePrice.isPriceCalculated"
                        />
                    </div>

But I can write for example 155.00 or 155.56. I need to limit it with 100.00 because I use this to write percents.

I tried to use this regex private regex: RegExp = new RegExp(/^(\d{1,2}(\.\d{1,2})?)|(100(\.0{1,2})?)$/g); but I still can use 150 percents.

How I can solve this problem?

like image 372
Eugene Sukh Avatar asked Dec 07 '25 05:12

Eugene Sukh


1 Answers

It should match all positive numbers starting 0, 0.0, 0.00 to 100, 100.0, 100.00

Regex:

^(\d{1,2}|\d{1,2}\.\d{1,2}|100\.[0]{1,2}|100)$

https://regex101.com/r/S9fbY7/3


Update:

you need to allow . to be typed beacuase 50. is not a valid pattern but 50.8 is but every keystroke validates the whole regex, so you need to update your code bypass validation when . is pressed do nothing and then on blur if value ends with dot maybe remove the value or remove the dot or add 00 after the dot

Ignored Keys:

private specialKeys: string[] = ['Backspace', 'Tab', 'End', 'Home', '.'];

On Blur you want to validate value ending with .. Note choose any one of the option based on your use case.

if (val.endsWith('.')) {
  // Option 1 strip the . (dot)
  this.el.nativeElement.value = val.substring(0, val.length - 1); 

  // Option 2 add 00 after the . (dot)
  this.el.nativeElement.value = val + '00'; 

  // Option 3 remove the value all together
  this.el.nativeElement.value = ''; 
}

Final Code:

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

@Directive({
  exportAs: 'decimal-number-directive',
  selector: 'decimal-number-directive, [decimal-number-directive]',
})
export class DecimalNumberDirective {
  private regex: RegExp = new RegExp(/^(\d{1,2}|\d{1,2}\.\d{1,2}|100\.[0]{1,2}|100)$/g);
  private specialKeys: string[] = ['Backspace', 'Tab', 'End', 'Home', '.'];
  constructor(private el: ElementRef) { }
  @HostListener('keydown', ['$event'])
  onKeyDown(event: KeyboardEvent): void {
    if (this.specialKeys.indexOf(event.key) !== -1) {
      return;
    }

    const current: string = this.el.nativeElement.value;
    const next: string = current.concat(event.key);
    if (next && !String(next).match(this.regex)) {
      event.preventDefault();
    }
  }

  @HostListener('blur', [])
  onBlur(): void {
    const val = this.el.nativeElement.value;
    if (val.endsWith('.')) {
      this.el.nativeElement.value = val.substring(0, val.length - 1); // Option 1 strip the .
      // this.el.nativeElement.value = val + '00'; // Option 2 add 00 after the .
      // this.el.nativeElement.value = ''; // Option 3 remove the value all together
    }
  }
}
like image 50
joyBlanks Avatar answered Dec 08 '25 19:12

joyBlanks