Reputation: 3009
I have an input that I want to be displayed like currency. I want only two decimal places to be allowed and for it to only allow numbers while automatically adding commas when necessary. Basically, if the user types "12345", I want the input to automatically display as "12,345.00". "12,345" would be acceptable too, but if they type in "12345.5" then it would need to be displayed as "12,345.50". I'm trying to use pipes to accomplish this and decided to use the "number" pipe since I don't want a currency symbol shown (I already have a dollar sign as a label before the input).
Here is my code:
<input [ngModel]="Amount | number: '1.2-2'" (ngModelChange)="updateAmount($event)" class="form-control" id="Amount" name="Amount" tabindex="4" type="number" autocomplete="off">
I'm having a few problems.
Invalid argument '11.00a' for pipe 'DecimalPipe'
After this error, the filter completely stops working.
If I set the input to type="number"
and I type in 1234, the value will be 1,234, but the input will disappear and I will get the following message in my console:
The specified value "1,234" is not a valid number. The value must match to the following regular expression: -?(\d+|\d+.\d+|.\d+)([eE][-+]?\d+)?
Using JQuery Inputmask gives me the results I want in terms of restricting/displaying the input, but it breaks my ngModel and sets the value to empty, so that isn't an option for me unless someone knows a way around that.
Are there changes I can make to my pipe to get me the results I want? How can I get this to work?
Upvotes: 5
Views: 6026
Reputation: 8335
Here is the aforementioned inspired directive for masking the input: https://plnkr.co/edit/aBvO2F?p=preview
import { Directive } from "@angular/core";
import { NgControl } from "@angular/forms";
@Directive({
selector: '[ngModel][decimal]',
host: {
'(ngModelChange)': 'onInputChange($event)'
}
})
export class DecimalMask {
constructor(public model: NgControl) {}
onInputChange(event, backspace) {
var valArray = event.toString().split('.') : [];
for(var i = 0; i < valArray.length; ++i) {
valArray[i] = valArray[i].replace(/\D/g, '');
}
var newVal: number;
if(valArray.length === 0) {
newVal = '';
}
else {
let matches = valArray[0].match(/[0-9]{3}/mig);
if(matches !== null && valArray[0].length > 3) {
let commaGroups = Array.from(Array.from(valArray[0]).reverse().join('').match(/[0-9]{3}/mig).join()).reverse().join('');
let replacement = valArray[0].replace(commaGroups.replace(/\D/g, ''), '');
newVal = (replacement.length > 0 ? replacement + "," : "") + commaGroups;
} else {
newVal = valArray[0];
}
if(valArray.length > 1) {
newVal += "." + valArray[1].substring(0,2);
}
}
// set the new value
this.model.valueAccessor.writeValue(newVal);
}
}
Input element looks like:
<input decimal [(ngModel)]="Amount"
class="form-control" id="Amount" name="Amount" tabindex="4" autocomplete="off">
Check guard if last character is alpha or length past decimals > 2:
ngDoCheck() {
console.log(this.Amount);
if(this.Amount) {
this.Amount = this.Amount.replace(/[A-Za-z]/g, '');
if(this.Amount.indexOf('.') !== -1) {
var arrayVals = this.Amount.split('.');
this.Amount = arrayVals[0] + "." + arrayVals[1].slice(0,2);
}
}
}
Upvotes: 3