Is it possible to implement an input
that allows to type only numbers inside without manual handling of event.target.value
?
In React, it is possible to define value
property and afterwards input change will be basically bound to the value (not possible to modify it without value
change). See example. And it works just fine without any efforts.
In Angular 2 it is possible to define [value]
, but it will just set the value initially, and afterwards input
is not prevented from the modifications.
I was playing around with ngModel
and [value] / (input)
, see example.
But in both implementation there is essential problem:
How to do that simple (from the first glance) component, without manually handling event.target.value
?...
UPDATE I am not looking for native HTML5 input[number]
element here. Numbers input here is just for the example - there could be way more tasks when i need to restrict input text.
Moreover, input[number]
is 1) not restricting me from typing 10ddd
and 2) (less important) contains arrows that i do not need.
And the problem here is to prevent user from typing something beyond the restricted values, instead of allow to input anything and validate it afterwards
This question is related to
angular
Anoher one
<form [formGroup]="myForm" novalidate>
<input type="text" class="form-control" id="data" name="data"
formControlName="input3" #item (input)="change(item.value)">
</form>
{{myForm.value |json}}
change(value:string)
{
let lastchar = value.substr(value.length - 1);
if (!(new RegExp('[0-9]').test(lastchar)))
{
value=value.substr(0,value.length-1);
this.myForm.controls["input3"].setValue(value);
}
}
if you use from driven template
<input type="text" class="form-control" id="data" name="data"
[(ngModel)]="data" #item (input)="change(item)">
{{data}}
change(item:any)
{
let value=item.value;
let lastchar = value.substr(value.length - 1);
if (!(new RegExp('[0-9]').test(lastchar)))
{
value=value.substr(0,value.length-1);
item.value=this.data=value;
}
}
Update As @BikashBishwokarma comment, this not work if you insert a character in middle. We can change the function by some like
change(item:any)
{
let value=item.value;
let pos=item.selectionStart;
if (!(new RegExp('^[0-9]+$').test(value)))
{
item.value=this.data=value.replace(/[^0-9]+/g, '');
item.selectionStart = item.selectionEnd = pos-1;
}
}
See, how mainten the cursor position
In HTML in <input>
field write: (keypress)="onlyNumberKey($event)"
and in ts file write:
onlyNumberKey(event) {
return (event.charCode == 8 || event.charCode == 0) ? null : event.charCode >= 48 && event.charCode <= 57;
}
Below is working solution using NgModel
Add variable
public Phone:string;
In html add
<input class="input-width" [(ngModel)]="Phone" (keyup)="keyUpEvent($event)"
type="text" class="form-control" placeholder="Enter Mobile Number">
In Ts file
keyUpEvent(event: any) {
const pattern = /[0-9\+\-\ ]/;
let inputChar = String.fromCharCode(event.keyCode);
if (!pattern.test(inputChar)) {
// invalid character, prevent input
if(this.Phone.length>0)
{
this.Phone= this.Phone.substr(0,this.Phone.length-1);
}
}
}
Tested Answer By me:
form.html
<input type="text" (keypress)="restrictNumeric($event)">
form.component.ts:
public restrictNumeric(e) {
let input;
if (e.metaKey || e.ctrlKey) {
return true;
}
if (e.which === 32) {
return false;
}
if (e.which === 0) {
return true;
}
if (e.which < 33) {
return true;
}
input = String.fromCharCode(e.which);
return !!/[\d\s]/.test(input);
}
A few of the answers did not work for me so I took the best bits from some of the answers (thanks guys) and created an Angular 5 Directive that should do the job (and more) for you. It maybe not perfect but it offers flexibility.
import { Directive, HostListener, ElementRef, Input, Renderer2 } from '@angular/core';
@Directive({
selector: '[appInputMask]'
})
export class InputMaskDirective {
@Input('appInputMask') inputType: string;
showMsg = false;
pattern: RegExp;
private regexMap = { // add your own
integer: /^[0-9 ]*$/g,
float: /^[+-]?([0-9]*[.])?[0-9]+$/g,
words: /([A-z]*\\s)*/g,
point25: /^\-?[0-9]*(?:\\.25|\\.50|\\.75|)$/g,
badBoys: /^[^{}*+£$%\\^-_]+$/g
};
constructor(public el: ElementRef, public renderer: Renderer2) { };
@HostListener('keypress', ['$event']) onInput(e) {
this.pattern = this.regexMap[this.inputType]
const inputChar = e.key;
this.pattern.lastIndex = 0; // dont know why but had to add this
if (this.pattern.test(inputChar)) {
// success
this.renderer.setStyle(this.el.nativeElement, 'color', 'green');
this.badBoyAlert('black');
} else {
this.badBoyAlert('black');
//do something her to indicate invalid character
this.renderer.setStyle(this.el.nativeElement, 'color', 'red');
e.preventDefault();
}
}
badBoyAlert(color: string) {
setTimeout(() => {
this.showMsg = true;
this.renderer.setStyle(this.el.nativeElement, 'color', color);
}, 2000)
}
}
HTML
<input class="form-control" appInputMask="badBoys">
<input type="number" onkeypress="return event.charCode >= 48 && event.charCode <= 57" ondragstart="return false;" ondrop="return false;">
Input filed only accept numbers, But it's temporary fix only.
After did lot of research finally I create a function which full fill the requirement. The function which I created restrict all special character and allow only alphabets and number.. and that function works fine for both either you did copy paste and typing both. Hope it works :)
public inputValidator(event: any) {
//console.log(event.target.value);
const pattern = /^[a-zA-Z0-9]*$/;
//let inputChar = String.fromCharCode(event.charCode)
if (!pattern.test(event.target.value)) {
event.target.value = event.target.value.replace(/[^a-zA-Z0-9]/g, "");
// invalid character, prevent input
}
}
<input type="text" [(ngModel)]="abc.abc" (input)="inputValidator($event)" />
How you use -
1) Add above method in your class component of ts file.
2) Call method inputValidator($event) on input event..
You can use the HTML5 input of type number
It does not accept any characters in its declaration
<input type="number" [(model)]='myvar' min=0 max=100 step=5 />
Here is an example of its usage with angular 2 [(model)]
To catch all the event surrounding model changes, can consider using
<input (ngModelChange)="inputFilter($event)"/>
It will detect copy / paste, keyup, any condition that changes the value of the model.
And then:
inputFilter(event: any) {
const pattern = /[0-9\+\-\ ]/;
let inputChar = String.fromCharCode(event.charCode);
if (!pattern.test(inputChar)) {
// invalid character, prevent input
event.preventDefault();
}
}
In component.ts add this function
_keyUp(event: any) {
const pattern = /[0-9\+\-\ ]/;
let inputChar = String.fromCharCode(event.key);
if (!pattern.test(inputChar)) {
// invalid character, prevent input
event.preventDefault();
}
}
In your template use the following
<input(keyup)="_keyUp($event)">
This will catch the input before angular2 catches the event.
I think a custom ControlValueAccessor is the best option.
Not tested but as far as I remember, this should work:
<input [(ngModel)]="value" pattern="[0-9]">
The inputmask plugin does the best job of this. Its extremely flexible in that you can supply whatever regex you like to restrict input. It also does not require JQuery.
Step 1: Install the plugin:
npm install --save inputmask
Step2: create a directive to wrap the input mask:
import {Directive, ElementRef, Input} from '@angular/core';
import * as Inputmask from 'inputmask';
@Directive({
selector: '[app-restrict-input]',
})
export class RestrictInputDirective {
// map of some of the regex strings I'm using (TODO: add your own)
private regexMap = {
integer: '^[0-9]*$',
float: '^[+-]?([0-9]*[.])?[0-9]+$',
words: '([A-z]*\\s)*',
point25: '^\-?[0-9]*(?:\\.25|\\.50|\\.75|)$'
};
constructor(private el: ElementRef) {}
@Input('app-restrict-input')
public set defineInputType(type: string) {
Inputmask({regex: this.regexMap[type], placeholder: ''})
.mask(this.el.nativeElement);
}
}
Step 3:
<input type="text" app-restrict-input="integer">
Check out their github docs for more information.
I use this one:
import { Directive, ElementRef, HostListener, Input, Output, EventEmitter } from '@angular/core';
@Directive({
selector: '[ngModel][onlyNumber]',
host: {
"(input)": 'onInputChange($event)'
}
})
export class OnlyNumberDirective {
@Input() onlyNumber: boolean;
@Output() ngModelChange: EventEmitter<any> = new EventEmitter()
constructor(public el: ElementRef) {
}
public onInputChange($event){
if ($event.target.value == '-') {
return;
}
if ($event.target.value && $event.target.value.endsWith('.')) {
return;
}
$event.target.value = this.parseNumber($event.target.value);
$event.target.dispatchEvent(new Event('input'));
}
@HostListener('blur', ['$event'])
public onBlur(event: Event) {
if (!this.onlyNumber) {
return;
}
this.el.nativeElement.value = this.parseNumber(this.el.nativeElement.value);
this.el.nativeElement.dispatchEvent(new Event('input'));
}
private parseNumber(input: any): any {
let trimmed = input.replace(/[^0-9\.-]+/g, '');
let parsedNumber = parseFloat(trimmed);
return !isNaN(parsedNumber) ? parsedNumber : '';
}
}
and usage is following
<input onlyNumbers="true" ... />
In html:
<input (keypress)="onlyNumber(event)"/>
In Component:
onlyNumber(evt) {
evt = (evt) ? evt : window.event;
var charCode = (evt.which) ? evt.which : evt.keyCode;
if (charCode > 31 && (charCode < 48 || charCode > 57)) {
return false;
}
return true;
}
I think this will solve your problem. I created one directive which filters input from the user and restricts number or text which you want.
This solution is for up to Ionic-3 and Angular-4 users.
import { Directive, HostListener, Input } from '@angular/core';
import { Platform } from 'ionic-angular';
/**
* Generated class for the AlphabateInputDirective directive.
*
* See https://angular.io/api/core/Directive for more info on Angular
* Directives.
*/
@Directive({
selector: '[keyboard-input-handler]' // Attribute selector
})
export class IonicKeyboardInputHandler {
@Input("type") inputType: string;
isNumeric: boolean = true;
str: string = "";
arr: any = [];
constructor(
public platForm: Platform
) {
console.log('Hello IonicKeyboardInputHandler Directive');
}
@HostListener('keyup', ['$event']) onInputStart(e) {
this.str = e.target.value + '';
this.arr = this.str.split('');
this.isNumeric = this.inputType == "number" ? true : false;
if(e.target.value.split('.').length === 2){
return false;
}
if(this.isNumeric){
e.target.value = parseInt(this.arr.filter( c => isFinite(c)).join(''));
}
else
e.target.value = this.arr.filter( c => !isFinite(c)).join('');
return true;
}
}
Source: Stackoverflow.com