2

I am new on Stack overflow so please forgive me If I am wrong anywhere. I am stuck with the problem in Angular 6, I have few input fields of type number and text and I want to prevent users from entering any character other than '.' (dot) and only enter positive numbers with a single dot for eg. "1.22" and not "1..2." or "-1.12" or "-111".

I have tried (keyup), (keypress) and (keydown) but each of them works really confusing for me. Please advice if there is any directive or any solution. in html

 <input type="number"(keyup)="numberOnlyWithDecimal($event,xyz)" name="weight [(ngModel)]="xyz" min="0" step="0.1"> 

in .ts

public textlength=0; numberOnlyWithDecimal(event, text): boolean { var regex = /^\d+(\.\d+)?$/; const charCode = (event.which) ? event.which : event.keyCode; var text2 = text + '' var test = text2.split(".") if (text2) { this.textlength = test.length-1 ; } if(text == null && charCode == 46){ return false; } if (charCode != 46 && charCode > 31 && (charCode < 48 || charCode > 57)) { return false; } if (!regex.test(charCode)) { return false } if (charCode === 46 && this.textlength ===1 ) { return false } return true; 

}

2
  • Right mouse click and select "paste" will bypass any attempts to limit when keys a user can press. Commented Jul 22, 2019 at 17:42
  • Actually pasting is not the issue in the project I am working. I just want that user can only enter positive values with maximum one dot. Commented Jul 22, 2019 at 17:46

3 Answers 3

2

Here you go, complete working solution for you :

1) Directive

 @Directive({ selector: '[appNumbersOnly]' }) export class NumbersOnlyDirective { private regex: RegExp = new RegExp(/^-?[0-9]+(\.[0-9]*){0,1}$/g); private specialKeys: Array<string> = ['Backspace', 'Tab']; constructor(private el: ElementRef) { } @HostListener('keydown', ['$event']) onKeyDown(event: KeyboardEvent) { 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(); } } } 

2) Usage in html

<input type="text" name="weight" appNumbersOnly [(ngModel)]="xyz" /> 

Stackblitz here for reference

Sign up to request clarification or add additional context in comments.

5 Comments

@yanky_carnky Thanks for the solution. It is working perfectly fine in stackblitz but for some reason, in my project, I can input two consecutive decimals. this is the HTML code <input type="number" appNumbersOnly name="weight" [(ngModel)]="anthropometry.body_measurements.weight.measure (ngModelChange)="onParamsChange($event)" min="0" step="0.1">
can you share your stackblitz
fixed (y) please check, now you no need to address type as number make it text instead
yes I now can see it working with type="text" but the project required to have a type number because of the upper and lower buttons in input. Is there any way to achieve this in type="number"?
@ShubhamDubey hide it using css
2

Finally, after loads of brainstorming, I have found a working solution for me. I would like to thanks all for helping me, you guys are savior.

I have used @yanky_cranky code and modified it a little bit and it worked for both number and text input type. Here is the code.

<input type="number" name="weight" appNumbersOnly [(ngModel)]="xyz"/> 

Directive:

import { Directive, ElementRef, HostListener } from "@angular/core"; @Directive({ selector: '[appNumbersOnly]' }) export class NumbersOnlyDirective { public text; private regex: RegExp = new RegExp(/^-?[0-9]+(\.[0-9]*){0,1}$/g); private specialKeys: Array<string> = ['Backspace', 'Tab']; constructor(private el: ElementRef) { } @HostListener('keypress', ['$event']) onKeyDown(event: KeyboardEvent) { if (this.specialKeys.indexOf(event.key) !== -1) { return; } const current: string = this.el.nativeElement.value; const next: string = current.concat(event.key); if(next.includes('.')){ if(this.text == next){ event.preventDefault(); } this.text= next; } if ((next && !String(next).match(this.regex))) { event.preventDefault(); } } } 

Comments

1

you can create your custom directive

import { Directive, ElementRef, HostListener, Input } 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', '-']; @Input('appTwoDigitDecimaNumber') decimal:any; constructor(private el: ElementRef) { } @HostListener('keydown', ['$event']) onKeyDown(event: KeyboardEvent) { // Allow Backspace, tab, end, and home keys if(this.decimal){ if (this.specialKeys.indexOf(event.key) !== -1) { return; } let current: string = this.el.nativeElement.value; let next: string = current.concat(event.key); if (next && !String(next).match(this.regex)) { event.preventDefault(); } }else{ const charCode = (event.which) ? event.which : event.keyCode; if (charCode > 31 && (charCode < 48 || charCode > 105)) { event.preventDefault(); } return; } } 

Usage

<input type="text" [appTwoDigitDecimaNumber]="true"> 

I hope it will help you a lot.

Note : you can use it any number type field where you want use just add [appTwoDigitDecimaNumber]="true" if you dont want to use then add [appTwoDigitDecimaNumber]="false". Bacause i have use these directive in dynamic forms that why i have set it base on true or false. You can use it in Dynamic form also

3 Comments

I am really thankful for your help, but the input is accepting multiple decimals and also negative numbers and even I can type multiple minus sign whereas user must not allowed to enter any negative value or minus sign and also no multiple dots.
You just need to change here regex pattern
Sorry but I don't have much knowledge about the regex pattern.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.