Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 8 Input validation accept only numbers

Tags:

angular

I'm creating dynamic input field it will accept all type values. I need to restrict only numbers to be enter.

template:

<tr  *ngFor="let item of rowData">
    <ng-container *ngFor="let hitem of columnDefs" >
      <td *ngIf="!hitem.dropdown; else selectDrop">
        <span *ngIf="hitem.edit;else content">
          <div *ngIf="editing">
          <input [required]="required"  [name]="item[hitem.field]" [(ngModel)]="item[hitem.field]" />
          </div>
          <div *ngIf="!editing">
            {{item[hitem.field]}}
          </div>
        </span>
      <ng-template #content>content here... {{item[hitem.field]}} </ng-template>
      </td>
      <ng-template #selectDrop>
        <td>
          <select [(ngModel)]="item[hitem.field]">
            <option *ngFor="let item of aplAry">{{item}}</option>
          </select>
        </td>
      </ng-template>
      </ng-container>
  </tr>

data:

mainHead = [{name:'', colspan:1}, {name:'Deatils', colspan:2}]
columnDefs = [
        {headerName: 'Make', field: 'make', edit:true },
        {headerName: 'Model', field: 'model', dropdown: true },
        {headerName: 'Price', field: 'price', edit:true}
];
aplAry = ['Celica','Mondeo','Boxter'];
    rowData = [
        { make: 'Toyota', model: 'Celica', price: 35000 },
        { make: 'Ford', model: 'Mondeo', price: 32000 },
        { make: 'Porsche', model: 'Boxter', price: 72000 }
];

Stackblitz example

like image 840
Rijo Avatar asked Nov 30 '22 08:11

Rijo


2 Answers

Here's a simpler approach using a directive.

export class NumbersOnlyDirective {
    @Input('field') field;

    constructor(private ngControl: NgControl) { }

    @HostListener('input', ['$event']) onInput(event): void {
        if (this.field === 'price') {
            const value = event.target.value;
            this.ngControl.control.setValue(parseFloat(value) || 0);
            if (value.slice(-1) === '.' && !value.slice(0, -1).includes('.')) {
                event.target.value = value;
            }
        }
    }
}

This directive will only allow decimal numbers to be entered. parseFloat removes the alphabets and other special characters. I have used || 0 as a fallback in case the field is emptied but if you don't want anything to display, simply use || '' instead. The if condition ensures that only one decimal point can be entered unlike when you use type="number" (type="number" will also change the ngModel to a string). The condition is placed after we update the control value so that if the last entered value is a ., the ngModel value will not include the . while the view will contain it.

Then use this directive in your template like below and pass the field value so that the this logic will only apply to the price field.

<input [required]="required" numbersOnly [field]="hitem.field" [name]="item[hitem.field]" [(ngModel)]="item[hitem.field]" />

Here is a working example on StackBlitz.

like image 43
nash11 Avatar answered Dec 06 '22 12:12

nash11


You can create a custom directive for only number. Stackblitz Demo

app.component.html

<input type="text" appOnlynumber/>

onlynumber.directive.ts

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

@Directive({
  selector: '[appOnlynumber]'
})
export class OnlynumberDirective {

  private navigationKeys = [
    'Backspace',
    'Delete',
    'Tab',
    'Escape',
    'Enter',
    'Home',
    'End',
    'ArrowLeft',
    'ArrowRight',
    'Clear',
    'Copy',
    'Paste'
  ];
  inputElement: HTMLElement;
  constructor(public el: ElementRef) {
    this.inputElement = el.nativeElement;
  }

  @HostListener('keydown', ['$event'])
  onKeyDown(e: KeyboardEvent) {
    if (
      this.navigationKeys.indexOf(e.key) > -1 || // Allow: navigation keys: backspace, delete, arrows etc.
      (e.key === 'a' && e.ctrlKey === true) || // Allow: Ctrl+A
      (e.key === 'c' && e.ctrlKey === true) || // Allow: Ctrl+C
      (e.key === 'v' && e.ctrlKey === true) || // Allow: Ctrl+V
      (e.key === 'x' && e.ctrlKey === true) || // Allow: Ctrl+X
      (e.key === 'a' && e.metaKey === true) || // Allow: Cmd+A (Mac)
      (e.key === 'c' && e.metaKey === true) || // Allow: Cmd+C (Mac)
      (e.key === 'v' && e.metaKey === true) || // Allow: Cmd+V (Mac)
      (e.key === 'x' && e.metaKey === true) // Allow: Cmd+X (Mac)
    ) {
      // 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();
    }
  }

  @HostListener('paste', ['$event'])
  onPaste(event: ClipboardEvent) {
    event.preventDefault();
    const pastedInput: string = event.clipboardData
      .getData('text/plain')
      .replace(/\D/g, ''); // get a digit-only string
    document.execCommand('insertText', false, pastedInput);
  }

  @HostListener('drop', ['$event'])
  onDrop(event: DragEvent) {
    event.preventDefault();
    const textData = event.dataTransfer.getData('text').replace(/\D/g, '');
    this.inputElement.focus();
    document.execCommand('insertText', false, textData);
  }


}
like image 92
Krishna Rathore Avatar answered Dec 06 '22 11:12

Krishna Rathore