I want to filter user input when they type in an HTML text input.
I can do that in native HTML/JavaScript as shown in the following demo:
<form>
<label for="tracking">Tracking Number:</label>
<input
type="text"
id="tracking"
name="tracking"
pattern="^[A-Z]{2}\d{9}[A-Z]{2}$"
title="Format must be like AB123456789CD"
required
minlength="13"
maxlength="13"
/>
</form>
<script>
const input = document.getElementById('tracking');
input.addEventListener('input', () => {
console.log('input fired');
// Remove non-alphanumeric chars and force uppercase
input.value = input.value.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
});
</script>
In the image above, I'm typing a, b, +, - (filtering works like I want). StackBlitz demo: Filter user input (native)
Now, I've done the same thing using Angular (with a template-driven form) as shown in the following demo:
@Component({
selector: 'app-root',
template: `
<form>
<label for="tracking">Tracking Number:</label>
<input
type="text"
id="tracking"
name="tracking"
pattern="^[A-Z]{2}\d{9}[A-Z]{2}$"
title="Format must be like AB123456789CD"
required
minlength="13"
maxlength="13"
[ngModel]="trackingNumber"
(ngModelChange)="onTrackingChange($event)"
/>
</form>
`,
imports: [FormsModule],
})
export class App {
trackingNumber = '';
onTrackingChange(value: string) {
console.log('input fired');
// Remove non-alphanumeric characters and force uppercase
this.trackingNumber = value.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
}
}
In the image above, I'm typing a, b, +, - (filtering does NOT work like I want). StackBlitz demo: Filter user input (Angular)
As far as my Angular knowledge goes, this happens when the current ngModel value is the same as the new/filtered value, thus Angular does not trigger a change on the HTML text input.
How can I overcome this behavior in Angular?
Can I force Angular to trigger a change?
The user "novative" on the Angular discord found a solution by replacing (ngModelChange)
with (input)
+ manually updating the input value.
@Component({
selector: 'app-root',
template: `
<form>
<label for="tracking">Tracking Number:</label>
<input
type="text"
id="tracking"
name="tracking"
pattern="^[A-Z]{2}\d{9}[A-Z]{2}$"
title="Format must be like AB123456789CD"
required
minlength="13"
maxlength="13"
[ngModel]="trackingNumber"
(input)="onTrackingChange(box)"
#box
/>
</form>
`,
imports: [FormsModule],
})
export class App {
trackingNumber = '';
onTrackingChange(box: HTMLInputElement) {
console.log('input fired');
// Remove non-alphanumeric characters and force uppercase
this.trackingNumber = box.value = box.value.replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
}
}
Thanks to anyone who tried to help!