limit input type number to 2 place of decimal in angular 2
I got the solution using @pipe
import { Directive,Input,Inject, HostListener, ElementRef, OnInit } from "@angular/core";const PADDING = "000000";@Pipe({ name: "CurrencyPipe" })export class CurrencyPipe implements PipeTransform { transform(value: any, args: string[]): any { var clean = value.replace(/[^-0-9\.]/g, ''); var negativeCheck = clean.split('-'); var decimalCheck = clean.split('.'); if (negativeCheck[1] != undefined) { negativeCheck[1] = negativeCheck[1].slice(0, negativeCheck[1].length); clean = negativeCheck[0] + '-' + negativeCheck[1]; if (negativeCheck[0].length > 0) { clean = negativeCheck[0]; } } if (decimalCheck[1] != undefined) { decimalCheck[1] = decimalCheck[1].slice(0, 2); clean = decimalCheck[0] + '.' + decimalCheck[1]; } return clean; } parse(value: string, fractionSize: number = 2): string { var clean = value.replace(/[^-0-9\.]/g, ''); var negativeCheck = clean.split('-'); var decimalCheck = clean.split('.'); if (negativeCheck[1] != undefined) { negativeCheck[1] = negativeCheck[1].slice(0, negativeCheck[1].length); clean = negativeCheck[0] + '-' + negativeCheck[1]; if (negativeCheck[0].length > 0) { clean = negativeCheck[0]; } } if (decimalCheck[1] != undefined) { decimalCheck[1] = decimalCheck[1].slice(0, 2); clean = decimalCheck[0] + '.' + decimalCheck[1]; } return clean; }}
And Pipe Extends in my directive.
import { Directive, Input, Inject, HostListener, OnChanges, ElementRef, Renderer, AfterViewInit, OnInit } from "@angular/core";import { CurrencyPipe } from '../../shared/pipe/orderby';@Directive({ selector: "[CurrencyFormatter]" })export class CurrencyFormatterDirective { private el: HTMLInputElement; constructor( private elementRef: ElementRef, private currencyPipe: CurrencyPipe ) { this.el = this.elementRef.nativeElement; } ngOnInit() { this.el.value = this.currencyPipe.parse(this.el.value); } @HostListener("focus", ["$event.target.value"]) onFocus(value) { this.el.value = this.currencyPipe.parse(value); // opossite of transform } @HostListener("blur", ["$event.target.value"]) onBlur(value) { this.el.value = this.currencyPipe.parse(value); } @HostListener("keyup", ["$event.target.value"]) onKeyUp(value) { this.el.value = this.currencyPipe.parse(value); }}
Import Directive on your component
import { CurrencyFormatterDirective } from '../../shared/directive/showOnRowHover';import { CurrencyPipe } from '../../shared/pipe/orderby';providers: [CurrencyPipe, CurrencyFormatterDirective]
And Directive on your html Input
<input type="text" [(ngModel)]="invoiceDetail.InvoiceAmount" class="form-control" placeholder="Enter invoice amount" CurrencyFormatter>
See demo of below directive in Plnkr.
You can achieve this using the following directive :
import { Directive, ElementRef, HostListener, Input } from '@angular/core';@Directive({ selector: '[OnlyNumber]'})export class OnlyNumber { elemRef: ElementRef constructor(private el: ElementRef) { this.elemRef = el } @Input() OnlyNumber: boolean; @Input() DecimalPlaces: string; @Input() minValue: string; @Input() maxValue: string; @HostListener('keydown', ['$event']) onKeyDown(event) { let e = <KeyboardEvent> event; if (this.OnlyNumber) { if ([46, 8, 9, 27, 13, 110, 190].indexOf(e.keyCode) !== -1 || // Allow: Ctrl+A (e.keyCode == 65 && e.ctrlKey === true) || // Allow: Ctrl+C (e.keyCode == 67 && e.ctrlKey === true) || // Allow: Ctrl+X (e.keyCode == 88 && e.ctrlKey === true) || // Allow: home, end, left, right (e.keyCode >= 35 && e.keyCode <= 39)) { // 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('keypress', ['$event']) onKeyPress(event) { let e = <any> event let valInFloat: number = parseFloat(e.target.value) if(this.minValue.length) { // (isNaN(valInFloat) && e.key === "0") - When user enters value for first time valInFloat will be NaN, e.key condition is // because I didn't want user to enter anything below 1. // NOTE: You might want to remove it if you want to accept 0 if( valInFloat < parseFloat(this.minValue) || (isNaN(valInFloat) && e.key === "0") ) { e.preventDefault(); } } if(this.maxValue.length) { if(valInFloat > parseFloat(this.maxValue)) { e.preventDefault(); } } if (this.DecimalPlaces) { let currentCursorPos: number = -1; if (typeof this.elemRef.nativeElement.selectionStart == "number") { currentCursorPos = this.elemRef.nativeElement.selectionStart; } else { // Probably an old IE browser console.log("This browser doesn't support selectionStart"); } let dotLength: number = e.target.value.replace(/[^\.]/g, '').length // If user has not entered a dot(.) e.target.value.split(".")[1] will be undefined let decimalLength = e.target.value.split(".")[1] ? e.target.value.split(".")[1].length : 0; // (this.DecimalPlaces - 1) because we don't get decimalLength including currently pressed character // currentCursorPos > e.target.value.indexOf(".") because we must allow user's to enter value before dot(.) // Checking Backspace etc.. keys because firefox doesn't pressing them while chrome does by default if( dotLength > 1 || (dotLength === 1 && e.key === ".") || (decimalLength > (parseInt(this.DecimalPlaces) - 1) && currentCursorPos > e.target.value.indexOf(".")) && ["Backspace", "ArrowLeft", "ArrowRight"].indexOf(e.key) === -1 ) { e.preventDefault(); } } }}
The HTML usage is as follows:
<input type="text" OnlyNumber="true" DecimalPlaces="2" minValue="1.00" maxValue="999999999.00">
If you find any bugs with it please let me know in the comments below.
P.S: This directive is improved work upon this answer to validate decimal points.
<input type='number' step='0.01' value='0.00' placeholder='0.00' />
don't use Step
use step
and if still you want old browser's support you can opt for javascript code for same