Divyesh Savaliya
Divyesh Savaliya

Reputation: 2730

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]

Upvotes: 14

Views: 31857

Answers (5)

sai kiran
sai kiran

Reputation: 389

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

Upvotes: 0

Virendra Yadav
Virendra Yadav

Reputation: 410

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>

Upvotes: 24

felipesntsassis
felipesntsassis

Reputation: 31

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.

Upvotes: 3

TheParam
TheParam

Reputation: 10541

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"> 

Upvotes: 0

Velusamy Venkatraman
Velusamy Venkatraman

Reputation: 736

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}}

Upvotes: 0

Related Questions