Jeto gave me 90% of the solution, and with a couple of tweaks, managed to get the exact behaviour I was after
I followed This article and got to a state where the field was displaying correctly, but it was always showing the truncated value.
What I really wanted was a pure "mask" so that the user could give more than 2dps, but would only see 2dps for clarity and have a mouseover to show the entire figure.
I then used This article to expose the NgModel in the directive so that on focus, the raw value of the ngModel.viewmodel was shown instead of the truncated value
My directive now looks like this (minus the pipe for clarity. Its a cut and paste of the 1st article at the moment)
import { Directive, Input, HostListener, ElementRef, OnInit } from "@angular/core";
import { NgModel } from "@angular/forms";
import { DecimalPipe } from "./decimal-pipe";
@Directive({
selector: "[decimalFormatter][ngModel]",
providers: [NgModel]
})
export class DecimalFormatterDirective implements OnInit {
private el: HTMLInputElement;
@Input('decimals') decimals: number;
constructor(
private elementRef: ElementRef,
private decimalPipe: DecimalPipe,
private ngModel: NgModel
) {
this.el = this.elementRef.nativeElement;
}
ngOnInit() {
if (this.decimals == null)
this.decimals = 2;
console.log(this.el);
console.log(this.ngModel);
this.el.value = this.decimalPipe.transform(this.el.value, this.decimals);
}
@HostListener("focus", ["$event.target.value"])
onFocus(value) {
console.log(this.el);
console.log(this.ngModel);
this.el.value = this.ngModel.viewModel; // opossite of transform
}
@HostListener("blur", ["$event.target.value"])
onBlur(value) {
console.log(this.el);
console.log(this.ngModel);
this.el.value = this.decimalPipe.transform(value, this.decimals);
}
}
EDIT: Small update
I changed the pipe it was calling from the one in the first article to the actual number pipe that the Angular uses so its now more of a wrapper for the Angular pipe that works with two way binding.
You also get to pass in the angular number formatting style, for example 2.2-6
Hopefully this helps someone coming across the same issue in the future!
The Directive :
import { Directive, Input, HostListener, ElementRef, OnInit } from "@angular/core";
import { NgModel } from "@angular/forms";
import { DecimalFormatPipe } from "./decimal-format-pipe";
@Directive({
selector: "[decimalFormatter][ngModel]",
providers: [NgModel]
})
export class DecimalFormatterDirective implements OnInit {
private el: HTMLInputElement;
@Input('decimals') decimals: string;
constructor(private elementRef: ElementRef,
private ngModel: NgModel,
private decimalFormatPipe: DecimalFormatPipe) {
this.el = this.elementRef.nativeElement;
}
ngOnInit() {
if (this.decimals == null)
this.decimals = "2.0-6";
console.log(this.el.value, this.decimals);
this.el.value = this.decimalFormatPipe.transform(this.el.value, this.decimals);
}
@HostListener("focus", ["$event.target.value"])
onFocus(value) {
console.log(this.el.value, this.decimals);
this.el.value = this.ngModel.viewModel; //Display the raw value on the model
}
@HostListener("blur", ["$event.target.value"])
onBlur(value) {
console.log(this.el.value, this.decimals);
this.el.value = this.decimalFormatPipe.transform(this.el.value, this.decimals);
}
}
The Pipe Wrapper
import { Pipe, PipeTransform, Inject, LOCALE_ID } from '@angular/core'
import { DecimalPipe } from '@angular/common';
@Pipe({ name: 'decimalFormatPipe' })
export class DecimalFormatPipe implements PipeTransform {
constructor(@Inject(LOCALE_ID) private locale: string) {}
transform(value: any, args: string) {
let pipe = new DecimalPipe(this.locale);
return pipe.transform(value, args);
}
}
And usage on an Input
<input #myNumberInputCtrl="ngModel"
name="myNumberInput"
spellcheck="false"
placeholder="Enter a Number.."
[(ngModel)]="myNumberModel"
required
decimalFormatter
[decimals]="'0.0-6'"
/>