Limit input field to two decimal places - Angular 5

Answer provided by @Sanoj_V can be improved:

1) you cannot use the arrow keys to edit the number, you can just add digits at the end or you have to click where you want to change the number.

2) once you have two decimals inserted you can only use backspace so either removing the last decimal or clicking somewhere else and removing a digit, but you cannot add anything so you can't change a digit by replacing it.

To solve that just replace : private specialKeys: Array<string> = ['Backspace', 'Tab', 'End', 'Home', '-'];

by: private specialKeys: Array<string> = ['Backspace', 'Tab', 'End', 'Home', '-', 'ArrowLeft', 'ArrowRight'];

Then replace: let next: string = current.concat(event.key);

by: const next: string = [current.slice(0, position), event.key, current.slice(position)].join('');

then add this line just above: const position = this.el.nativeElement.selectionStart;

Thanks @Sanoj_V for this directive, I've spent all day trying to figure out how to deal with currencies input.


First create Directive for limit the two decimal places in typescript like this:

import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
  selector: '[appTwoDigitDecimaNumber]'
})
export class TwoDigitDecimaNumberDirective {
  private regex: RegExp = new RegExp(/^\d*\.?\d{0,2}$/g);
  private specialKeys: Array<string> = ['Backspace', 'Tab', 'End', 'Home', '-', 'ArrowLeft', 'ArrowRight', 'Del', 'Delete'];
  constructor(private el: ElementRef) {
  }
  @HostListener('keydown', ['$event'])
  onKeyDown(event: KeyboardEvent) {
    console.log(this.el.nativeElement.value);
    // Allow Backspace, tab, end, and home keys
    if (this.specialKeys.indexOf(event.key) !== -1) {
      return;
    }
    let current: string = this.el.nativeElement.value;
    const position = this.el.nativeElement.selectionStart;
    const next: string = [current.slice(0, position), event.key == 'Decimal' ? '.' : event.key, current.slice(position)].join('');
    if (next && !String(next).match(this.regex)) {
      event.preventDefault();
    }
  }
}

Inject Directive in your app.module.ts. In your html use that directive like this:

<input type="textbox" [(ngModel)]="InputValue" appTwoDigitDecimaNumber>

Here is working example in Angular 4/5/6: Limit Two decimal places number validation

Hope this will help you!!!!


@Sanoj_v and user3803848 solution works great, but there is one more bug in IE. When user uses dot sign from numeric keyboard, there is emitted 'Decimal' key event and directive not work properly.

Fix for this:

    const next: string = [current.slice(0, position), event.key === 'Decimal' ? '.' : event.key, current.slice(position)].join('');

Just in case, I added '.' and ',' char to regex, that checks user input.

Below whole directive

@Directive({
  selector: '[appTwoDigitDecimalNumber]',
})
export class TwoDigitDecimaNumberDirective {
  private regex: RegExp = new RegExp(/^\d+[.,]?\d{0,2}$/g);// user can put . or , char.
// input also cannot start from , or .
  private specialKeys: Array<string> = ['Backspace', 'Tab', 'End', 'Home', '-', 'ArrowLeft', 'ArrowRight', 'Del', 'Delete'];

  constructor(private el: ElementRef) {
  }

  @HostListener('keydown', ['$event'])
  onKeyDown(event: KeyboardEvent) {
    if (this.specialKeys.includes(event.key)) {
      return;
    }
    const current: string = this.el.nativeElement.value;
    const position = this.el.nativeElement.selectionStart;
    const next: string = [current.slice(0, position), event.key == 'Decimal' ? '.' : event.key, current.slice(position)].join('');
    if (next && !String(next).match(this.regex)) {
      event.preventDefault();
    }
  }
}

You should remember, that is still possible to paste some wrong data into input. That's why, you probably need one more validation, maybe on Input event to prevent pasting wrong data.


Easiest way to achieve that would be binding to the "keypress" event and validate with a regex expression whether that's a valid input or not.

<input type="number" ... placeholder="Cost Price"  (keypress)="validateNumber($event)" />

And then the validateNumber would be something like:

validateNumber(e: any) {
    let input = String.fromCharCode(e.charCode);
    const reg = /^\d*(?:[.,]\d{1,2})?$/;

    if (!reg.test(input)) {
      e.preventDefault();
    }
}