Angular 4 input only numbers Directive



I was working on a project in Angular 4 and needed to implement input fields that only accept numerical values. My first thought was to simply add the HTML5 type=”number” to the input. Unfortunately, this isn’t supported in Internet Explorer 10 and some of the clients would most likely be using Internet Explorer 10. My only other option was to implement a directive. Thanks to this StackOverflow answer, I was able to modify it to my needs.

Number Directive:

Begin by creating a separate file called number.directive.ts. Put the following in that file:

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

@Directive({
 selector: '[myNumberOnly]'
})
export class NumberOnlyDirective {
 // Allow decimal numbers and negative values
 private regex: RegExp = new RegExp(/^-?[0-9]+(\.[0-9]*){0,1}$/g);
 // Allow key codes for special events. Reflect :
 // Backspace, tab, end, home
 private specialKeys: Array<string> = [ 'Backspace', 'Tab', 'End', 'Home', '-' ];

constructor(private el: ElementRef) {
 }
 @HostListener('keydown', [ '$event' ])
 onKeyDown(event: KeyboardEvent) {
 // Allow Backspace, tab, end, and home keys
 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();
 }
 }
}

Notice the regular expression used:

RegExp = new RegExp(/^-?[0-9]+(\.[0-9]*){0,1}$/g);

This allows positive and negative decimal values to be entered.

Module

Inside of your module, make sure you import the nuumber.directive.ts file and pass it into your module’s declarations:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router';
import { NumberOnlyDirective } from './number.directive';
import { FormsModule } from '@angular/forms';
import { NgClass } from '@angular/common';
import { appComponent } from './temperature.component';

@NgModule({
 imports: [
 CommonModule,
 FormsModule,
 // HttpModule,

],
 providers: [],
 declarations: [appComponent, NumberOnlyDirective],
 bootstrap:[appComponent]
})
export class appModule { }

HTML

Finally, in your component’s HTML you can utilize the directive like so:

<input myNumberOnly name="min" placeholder="Enter Value" [(ngModel)]="my.minVal">

That’s all it takes, Angular 4 input numbers only directive.  This should also work for Angular 5.

 

6 thoughts on “Angular 4 input only numbers Directive

  1. Can you share how do you write Jasmine test for this? I find it quire difficult…. I guess we need a component with input control where we apply the directive, but what I have as a problem is that the value of the input is not updating when I simulate const event = new KeyboardEvent(‘keydown’, { key: ‘1’ }); …. thanks

    import { TestBed, ComponentFixture } from ‘@angular/core/testing’;
    import { PositiveNumberOnlyDirective } from ‘./positive.number.directive’;
    import { Component, DebugElement, Input, OnInit } from ‘@angular/core’;
    import { By } from ‘@angular/platform-browser’;
    import { FormsModule } from ‘@angular/forms’;

    @Component({
    template: “
    })
    class TestPositiveNumberComponent {
    public didi: any;
    }

    describe(‘Directive: PositiveNumberOnly’, () => {
    let component: TestPositiveNumberComponent;
    let fixture: ComponentFixture;
    let inputEl: DebugElement;
    beforeEach(() => {
    TestBed.configureTestingModule({
    declarations: [TestPositiveNumberComponent, PositiveNumberOnlyDirective]
    });
    fixture = TestBed.createComponent(TestPositiveNumberComponent);
    component = fixture.componentInstance;
    inputEl = fixture.debugElement.query(By.css(‘input’));
    });

    it(‘entering not number input’, () => {

    const event = new KeyboardEvent(‘keydown’, { key: ‘1’ });
    // // el.dispatchEvent(event);
    inputEl.nativeElement.dispatchEvent(event);

    fixture.detectChanges();
    fixture.whenStable().then(() => {
    expect(component.didi).toBe(1);
    expect(inputEl.nativeElement.value).toBe(”);

    });

    });
    });

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

    @Directive({
    selector: ‘[appPositiveNumberOnly]’
    })
    /**
    * Allows only positive number to be entered
    */
    export class PositiveNumberOnlyDirective {
    private regex: RegExp = new RegExp(‘^[0-9]+$’);
    private specialKeys: Array = [‘Backspace’, ‘Tab’, ‘End’, ‘Home’];
    constructor(private el: ElementRef) {
    }
    @HostListener(‘keydown’, [‘$event’])
    onKeyDown(event: KeyboardEvent) {
    // Allow Backspace, tab, end, and home keys
    if (this.specialKeys.indexOf(event.key) !== -1) {
    return;
    }
    const next: string = this.el.nativeElement.value.concat(event.key);
    if (next && !String(next).match(this.regex)) {
    event.preventDefault();
    }
    }
    }

  2. Thanks for sharing! but just to alert you an event past of the mouse is still possible enter other kind of characters

  3. its accepting before zeros don’t accept zeros before number. ex:0001 is accepting result will be 1 only i want

  4. Many may also want to add ‘Enter’,’ArrowLeft’,’ArrowRight’,’Escape’ to the specialKeys array. People should also know this won’t block pasting an invalid value into the box, so the value should still be validated.

Leave a Reply

Your email address will not be published. Required fields are marked *

Name *