This question is about restricting/validating the input when the user enters data into an input of type number.
The issue I have is that when the model first loads, any numbers that are integers or 1dp, get rendered with only 1dp. eg 40 or 40.0 both show as 40.0 (not as 40.00).
I have added this code so that after a user types a new value, it shows with 2dp:
in the template file:
(change)="setTwoNumberDecimal($event)"
in the component file:
setTwoNumberDecimal($event) {
$event.target.value = parseFloat($event.target.value).toFixed(2);
}
This works to show 2dp after the user changes the value.
I tried to write a directive that should format to 2dp when the data initially loads, but although the directive does fire, it does not change the value to 2dp.
import { Directive, ElementRef, Input, Renderer2 } from '@angular/core';
@Directive ({
selector: '[fbDecimalFormat]'
})
export class DecimalFormatDirective {
constructor(private el: ElementRef,
private renderer: Renderer2) {
//renderer.setAttribute(el, 'value', parseFloat(el.nativeElement.value).toFixed(2));
this.el.nativeElement.value = parseFloat(this.el.nativeElement.value).toFixed(2);
}
}
FYI the commented render line did not work (error: setAttribute not recognised) - it was an attempt to be platform independent.
So the question is: How can I get the input to render its initial value with 2dps?
Use JavaScript for validation input or use step=". 01" , which allows up to two decimal places on keypress input.
Use the toFixed() method to format a number to 2 decimal places, e.g. num. toFixed(2) . The toFixed method takes a parameter, representing how many digits should appear after the decimal and returns the result.
Rounding a decimal number to two decimal places is the same as rounding it to the hundredths place, which is the second place to the right of the decimal point. For example, 2.83620364 can be round to two decimal places as 2.84, and 0.7035 can be round to two decimal places as 0.70.
All numbers are stored as floating point numbers. These numbers can be Decimal (base 10), Hexadecimal (base 16) or Octal (base 8). In the above example, let first:number = 1; stores a positive integer as a number. let second: number = 0x37CF; stores a hexadecimal as a number which is equivalent to 14287.
Template Forms
The solution to this was to use the built-in DecimalPipe
(weirdly called number) and not use two-way binding for the model value - ie. from [(ngModel)] to [ngModel] and (ngModelChange)
<input type="number" step="0.01"
(change)="setTwoNumberDecimal($event)"
(ngModelChange)="item.value=$event"
[ngModelOptions]="{updateOn: 'blur'}"
[ngModel]="setting.decimal_value | number:'1.2-2'">
See this question for more info on splitting the [()] binding.
Notice also that the update fires only when the user leaves the control (blur) otherwise every time they type something it will update, which will be a frustrating UX (thanks to @Mihail's comment).
Reactive Forms
In response to the question in the comments: "Could this be used with reactive forms as well?"
The answer is:
No, using pipes with reactive forms is more complicated. You could use the pipe merely to display the value, like
<p>{{form.get('name').value | myPipe}}</p>
but I think the correct way is to use value accessor. More info here.
Number.toFixed(x) Formats any number for "x" number of trailing decimals. The number is rounded up, and "0"s are used after the decimal point if needed to create the desired decimal length. In template we can format the value and validating the values
value1 = 0
value2 = 0.0
<p>
{{value1.toFixed(2)}} - shows 0.00
{{value2.toFixed(2)}} - shows 0.00
</p>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With