'Ionic 4 ion-input allow number only, restrict alphabet and special character

I am creating an app in ionic4, I have a functionality where user can enter the only integer number (0-9), so I want to restrict any other character i.e alphabets, dot, plus everything.
I tried to restrict is using the following directive

 @HostListener('input', ['$event']) onInputChange(event) {
    this.inputElement = this._el.nativeElement.getElementsByTagName('input')[0];
    const initalValue = this.inputElement.value;
    this.inputElement.value = initalValue.replace(/[^0-9]*/g, '');
    if (initalValue !== this.inputElement.value) {
       event.stopPropagation();
    }
}

It is updating ngModel correctly but still, an invalid character is visible in the input field.

I tried another option as following

html

<ion-input type="text" placeholder="Enter number"
        [(ngModel)]="userCount" 
        name="userCount" 
        (ionInput)="countChange($event)">
 </ion-input>
 Usercount: {{userCount}}

Typescript

countChange(event) {
    event.target.value = event.target.value.replace(/[^0-9]*/g, '');
}

With above its printing value in HTML correct without invalid character, but its showing invalid character in input.

If I enter 5+ in input, the value in ngModel shows 5 but input field showing 5+

When I type 5++ and then type 5 again, input field shows 55 now.

How can I restrict input to accept only integer values [0-9]



Solution 1:[1]

You should use keypress event Here is the example TS File

  numberOnlyValidation(event: any) {
    const pattern = /[0-9.,]/;
    let inputChar = String.fromCharCode(event.charCode);

    if (!pattern.test(inputChar)) {
      // invalid character, prevent input
      event.preventDefault();
    }
  }

HTML File

<ion-input type="text" placeholder="Enter number"
        [(ngModel)]="userCount" 
        name="userCount" 
        (keypress)="numberOnlyValidation($event)"
 </ion-input>

It will resolve your issue.

Using directive in Ionic 5:

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

@Directive({
  selector: '[appIntegerInput]'
})
export class IntegerInputDirective {

  constructor() { }

  @HostListener('keypress', ['$event'])
  onInput(event: any) {
    const pattern = /[0-9]/; // without ., for integer only
    let inputChar = String.fromCharCode(event.which ? event.which : event.keyCode);

    if (!pattern.test(inputChar)) {
      // invalid character, prevent input
      event.preventDefault();
      return false;
    }
    return true;
  }

}

HTML File

<ion-input appIntegerInput inputmode="numeric" type="number"></ion-input>

Solution 2:[2]

I solved my problem purging the alphabetic characters input following these steps:

  1. I create a util class with method:

export class StringUtil {
 
    /**
     * Removes all non numeric characters from string.
     * @param str string
     */
    static removeNonNumerics = (str: string) => str.replace(/\D/g, '');

}
  1. Created my directive:

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

import { StringUtil } from 'src/app/shared/utils/string.util';

@Directive({
    selector: '[appInputInteger]'
})
export class InputIntegerDirective {

    constructor() { }

    @HostListener('input', ['$event'])
    onInput(event: any) {
        event.target.value = StringUtil.removeNonNumerics(event.target.value);
    }

}
  1. I've imported the InputIntegerDirective in my page module:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { IonicModule } from '@ionic/angular';

import { DeliveryTimePageRoutingModule } from './delivery-time-routing.module';

import { DirectivesModule } from 'src/app/shared/directives/directives.module';
import { UiModule } from 'src/app/shared/ui/ui.module';
import { DeliveryTimePage } from './delivery-time.page';

@NgModule({
    imports: [
        CommonModule,
        DirectivesModule,
        FontAwesomeModule,
        FormsModule,
        IonicModule,
        DeliveryTimePageRoutingModule,
        ReactiveFormsModule,
        UiModule
    ],
    declarations: [DeliveryTimePage]
})
export class DeliveryTimePageModule { }
  1. And finally used it at page:

<ion-input type="text" inputmode="numeric" formControlName="deliveryTime" maxlength="3" placeholder="Tempo de Entrega" [required]="true" appInputInteger>
</ion-input>

This directive worked well on the web browser and my mobile device too.

Solution 3:[3]

Change your code like this. I hope it will fix

countChange(event) {
   
   this.userCount += event.target.value.replace(/[^0-9]*/g, '');
}
<ion-input type="text" placeholder="Enter number"
         name="userCount" 
        (change)="countChange($event)">
 </ion-input>
 Usercount: {{userCount}}

Solution 4:[4]

Here is a very simple solution to your problem.

Step 1: Create a number-only directive and place it in a directive folder.

number-only.directive.ts

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

@Directive({
  selector: 'input[numbersOnly]'
})
export class NumberDirective {

  constructor(private _el: ElementRef) { }

  @HostListener('input', ['$event']) onInputChange(evt) {

    if (evt.which === 8 || evt.which === 0) {
        return true;
    }

    const regex = new RegExp("^[0-9\~]*$");
    var key = String.fromCharCode(!evt.charCode ? evt.which : evt.charCode);
    // console.log(regex.test(key))
    if (!regex.test(key)) {
        evt.preventDefault();
        return false;
    }
    return true;
  }

}

**Step 2: ** import it in a app.module file.

import { NumberDirective } from './directive/number-only.directive';
@NgModule({
  imports: [
    CommonModule,
  ],
  declarations: [NumberDirective],
  exports: []
})
export class AppModule { }

Step 3: Apply directive to input field like below.

  <input type="text" numbersOnly placeholder="Enter Mobile/Phone Number"> 

Solution 5:[5]

Hi i achived this challenge none of the above solutions worked may be because they are outdated i am not sure but the way it worked for is by creating an attribute

bufferValue="";
isPaste=false;
@Input() maxlength=100;
@HostListener('ionInput',[$event]) ionInput($event){
   if((this.bufferValue.length+1>=$event.target.value.length || this.isPaste) && $event.target.value.length<=this.maxlength){
    this.numberInput($event.target);
    $event.srcElement.children[0].value=$event.target.value;
}
   else{
   $event.target.value=this.bufferValue;
}
}
@HostListener('keyup',['$event']) onKeyUp($event){
  if(this.bufferValue.length+1>=$event.target.value.length && $event.target.value.length<=this.maxlength){
  this.numberInput($event.target);
  $event.srcElement.children[0].value=$event.target.value;
}
else{
  $event.target.value=this.bufferValue;
}
}
@HostListener('ionChange',['$event']) ionChange($event){
  if(this.isPaste && $event.target.value.length<=this.maxlength){
    this.numberInput($event.srcElement.children[0]);
    $event.srcElement.children[0].value=$event.target.value
    this.isPaste=true;
}
this.bufferValue=$event.target.value;
}
@HostListener('paste')paste(){
 this.isPaste=true;
}
numberInput(target){
 target.value=this.removeNonNumberValue(target.value);
 this.bufferValue=target.value;
}
removeNonNumberValue(value){
  return value.replace(/[^0-9]/g,'');
}

how ever it had its own challenges auto fill wont work and in iphone when scan alphabets it will be filled

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Renato Probst
Solution 2
Solution 3 Velusamy Venkatraman
Solution 4 Dharman
Solution 5 sai kiran