I have this problem where I am trying to implement a smart number input component which can be set to allow or disallow negative numbers. I have an (input) event listener on the <input> element, which runs a function that is supposed to apply a bunch of regex patterns to the value. The function seems to work correcly and the variable's value is being changed, but the value in the input doesn't update (bound to the input via [(ngModel)]).
Here are the code snippets (Angular v13.2.4):
//number-input.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-number-input',
templateUrl: './number-input.component.html',
styleUrls: ['./number-input.component.scss']
})
export class NumberInputComponent {
//basic variables
@Input() inputValue: string | number | null = null;
@Input() placeholder: string | number | undefined = undefined;
//allow negative numbers to be used
@Input('allow-negative') allowNegative: boolean = false; //this is set to false everywhere possible
//emit the number from the input on change
@Output('app-change') change = new EventEmitter<number>();
constructor() { }
onInput() {
let str = String(this.inputValue);
console.log(this.inputValue, str);
if (!this.allowNegative && str.match(/\-/g)) {
str = str.replace(/\-/g, '');
}
if (this.allowNegative && str.match(/(.+)-/g)) {
str = str.replace(/(.+)-/g, '$1');
}
if (str.match(/[^0-9,\.\-]/g)) {
str = str.replace(/[^0-9,\.\-]/g, '');
}
if (str.match(/,/g)) {
str = str.replace(/,/g, '.');
}
this.inputValue = Number(str);
console.log(this.inputValue, str);
}
onChange() {
this.change.emit(Number(this.inputValue));
}
}
<!-- number-input.component.html -->
<input type="text" [(ngModel)]="inputValue" (input)="onInput()" (change)="onChange()">
Cases I tested
| Input value | First console.log | Second console.log | What happens |
|---|---|---|---|
123 |
'123' '123' |
123 '123' |
Nothing, as is supposed to |
123a |
'123a' '123a' |
123 '123' |
Value in the input element doesn't update, but this.inputValue clearly does |
-123 |
'-123' '-123' |
123 '123' |
Value in the input element doesn't update, but this.inputValue clearly does |
123-4 |
'123-4' '123-4' |
123 '123' |
Value in the input element doesn't update, but this.inputValue clearly does |
Also, in all cases where the value in the input element doesn't update, typing in any number seems to update the input's value, and it displays properly. Typing in any other character does nothing.
Any ideas?
Edit
I came up with a solution, that doesn't involve ngModel:
onInput() method now accepts an event argument, which I use to directly edit the input element's value. Here is the code that ended up working:
onInput(event: Event) {
let inputEl = event.target as HTMLInputElement;
let str = String(inputEl.value);
// some regex matches here
this.inputValue = Number(str);
inputEl.value = str;
}