I ask myself if it possible to intercept an ngModel binding with an Angular directive.
For example:
template:
<input type="string" [(ngModel)]="numberVal" name="someName" appNumberInput>
component:
public numberVal: number;
directive:
selector: '[appNumberInput]'
// magic happens to convert a number to string and vice versa.
This problems comes up because it is not possible to use selectionStart
and selectionEnd
with `<input type="number>" (Get Cursor Position With Input type number and selectionStart/selectionEnd on input type="number" no longer allowed in Chrome).
I know, I could create a custom component which wraps a native input component. However, I wonder if this is solvable with only a custom directive.
I tried two directive prototypes:
- Implement NgValueAccessor:
@Directive({
selector: '[appNumberInput]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NumberInputDirective),
multi: true
}
]
})
export class NumberInputDirective implements ControlValueAccessor {
constructor(private el: ElementRef<HTMLInputElement>) {}
private onChange: (_: any) => void = () => {};
private onTouched = () => {};
writeValue(value: any): void {
this.el.nativeElement.value = value != null ? value : '';
}
registerOnChange(fn: (_: any) => void): void {
this.onChange = fn;
}
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
@HostListener('input', ['$event.target.value'])
onInput(value: string): void {
const parsedValue = parseFloat(value);
this.onChange(isNaN(parsedValue) ? null : parsedValue);
}
}
- Provide ngModel in the constructor:
@Directive({
selector: '[appCustomNgModelInterceptor]',
providers: [NgModel],
})
export class CustomNgModelInterceptorDirective {
constructor(private ngModel: NgModel) {
ngModel.valueChanges.pipe(tap((value) => {
console.log('changed value', value); // this line is never triggered.
}));
}
}
I would expect that the numberVal
would be transformed to a string for input bindung but parsed back as float for the output binding.
None of these versions will update the bounded value.