5

I am trying to make a inputNumber directive which will prevent typing (not highlighting the input when value is wrong, but even typing in wrong value):

a) letters and symbols, restrict only to [0-9] b) respect min and max params c) be in relation with other such directives in the view via greaterOrEqual / lessOrEqual properties.

This is my input-number.directive.ts:

import {Directive, HostListener, Input} from '@angular/core'; @Directive({ selector: '[inputNumber]' }) export class InputNumberDirective { @Input() min: number = 0; // will be input @Input() max: number = 100; // will be input @Input() greaterOrEqual: number = 23; // will be input @Input() lessOrEqual: number = 77; // will be input @HostListener('keypress', ['$event']) sanitizeValue(event: KeyboardEvent): boolean { const targetVal: number = Number((<HTMLInputElement>event.target).value); if (event.charCode >= 48 && event.charCode < 58) { if (this.min !== null && targetVal < this.min) { return false; } if (this.max !== null && targetVal > this.max) { return false; } if (this.greaterOrEqual !== null && targetVal < this.greaterOrEqual) { return false; } return !(this.lessOrEqual !== null && targetVal > this.lessOrEqual); } return false; } } 

This all works in terms of preventing typing letters/symbols, but when it comes to respecting numbers limiters user is still able to type them over and my purpose to prevent this. I found some SO threads (e.g. Don't allow typing numbers between max and min value) on this, but it didn't help me a lot.

9
  • Wouldn't is be easier to write your own validator? Commented Nov 30, 2017 at 12:44
  • Validator will not prevent typing in wrong value Commented Nov 30, 2017 at 12:45
  • But could prevent submiting a form Commented Nov 30, 2017 at 12:47
  • This is two way binding case where data is used later dynamically Commented Nov 30, 2017 at 12:48
  • personally, I would redesign that. Commented Nov 30, 2017 at 12:50

3 Answers 3

5

This is a directive (Stackblitz)I am sure will help your case, it doesn´t let other input values other than numbers but also it allows CTRL+C, CTRL+V among other usefull keys for inputs.

import { Directive, ElementRef, HostListener, Input } from '@angular/core'; @Directive({ selector: '[NumericInput]' }) export class NumericInput { constructor(private el: ElementRef) { } @Input() latestInputValue: number; @HostListener('keydown', ['$event']) onKeyDown(event) { let e = <KeyboardEvent> event; if (this.latestInputValue < 0 || this.latestInputValue > 100) { e.preventDefault(); } else if ([46, 8, 9, 27, 13, 110, 190].indexOf(e.keyCode) !== -1 || // Allow: Ctrl+A (e.keyCode === 65 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+C (e.keyCode === 67 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+V (e.keyCode === 86 && (e.ctrlKey || e.metaKey)) || // Allow: Ctrl+X (e.keyCode === 88 && (e.ctrlKey || e.metaKey)) || // Allow: home, end, left, right (e.keyCode >= 35 && e.keyCode <= 39)) { // let it happen, don't do anything return; } // Ensure that it is a number and stop the keypress if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) { e.preventDefault(); } } } 

HTML

<input NumericInput [latestInputValue]="someValue" [(ngModel)]="someValue" > 
Sign up to request clarification or add additional context in comments.

9 Comments

thanks for you effort, but my main concern is to resolve typing over min and max values, this is missing in your answer
edited answer, you should now get input value in latestInputValue so you can validate it
I eventually redesigned this logic and wrapped the input directive in a component, added increment/decrement functionality and value validation, but you were close :) tnx
This is really allowing me to start thinking in terms of the "Angular Way"
@Mohan remove the line under '// Allow: Ctrl+V' If you still want to paste only numbers, just add the logic where if you have a char you wont return the value
|
3

Your directive can also listener 'input' changes.

import { Directive,HostListener,ElementRef } from '@angular/core'; @Directive({ selector: '[customMax]' }) export class customDirective { private el: HTMLInputElement; constructor(private elementRef: ElementRef) { this.el = this.elementRef.nativeElement; } @HostListener('input',['$event'])onchange(event:any){ let value=this.el.value; let lastchar = value.substr(value.length - 1); let bool=lastchar.match(/[0-9]/); if (bool){ //if last character match a regExpr bool=parseInt(value)>=0 && parseInt(value)<100; //and the condition required } if (!bool){ //if it does not meet the conditions value=value.substr(0,value.length-1); this.el.value=value; //it's necesary dispatch the event 'input' manually let event = new Event('input', { bubbles: true }); this.el.dispatchEvent(event); } } 

Comments

-3

I suggest you to use Kendo, that simply allow you to have a min & max on its own component.

<kendo-numerictextbox [value]="value" [min]="0" [max]="100"> </kendo-numerictextbox> 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.