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?
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
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With