We are using Angular 17 along with Reactive forms in our project.
We have written a custom directive which formats the output to US phone number format 111-222-3333
.
What we are seeing is that when someone tries to copy a number into the field - the field gets formatted, but the validator is still saying it is not valid.
HTML Code:
<input matInput phoneFormatterDirective placeholder="Enter Phone" formControlName="phone"
class="inputEntry">
Typescript Code:
phone: new FormControl(null, [Validators.pattern('^[0-9]{3}-[0-9]{3}-[0-9]{4}$')])
Custom Directive Code:
import {Directive, HostListener} from '@angular/core';
@Directive({
selector: '[phoneFormatterDirective]'
})
export class PhoneFormatterDirective {
@HostListener('input', ['$event'])
onKeyDown(event: KeyboardEvent) {
event.preventDefault();
const input = event.target as HTMLInputElement;
console.log(input.value);
let trimmed = input.value
.replaceAll('-','')
.replaceAll('(','')
.replaceAll(')','')
.replaceAll(/\s+/g, '');
if (trimmed.length > 12) {
trimmed = trimmed.substr(0, 12);
}
let numbers = [];
numbers.push(trimmed.substr(0,3));
if(trimmed.substr(3,2)!=="")
numbers.push(trimmed.substr(3,3));
if(trimmed.substr(6,3)!="")
numbers.push(trimmed.substr(6,4));
input.value = numbers.join('-');
console.log(numbers.join("-"));
}
}
Let's say I am trying to paste (555) 123-1234
- the value gets formatted to 555-123-1234
, but the input says it is still invalid.
It would be valid if I deleted one character and then wrote it manually - which is a kind of strange behavior.
Currently, you are setting the formatted value to HtmlInputElement
's value, but it is not reflected in the form control's state.
I would suggest grabbing and setting the value from/to NgControl
in order to update the form control's state.
import { Directive, HostListener } from '@angular/core';
import { NgControl } from '@angular/forms';
@Directive({
selector: '[phoneFormatterDirective]',
standalone: true,
})
export class PhoneFormatterDirective {
constructor(public control: NgControl) {}
@HostListener('input', ['$event'])
onKeyDown(event: KeyboardEvent) {
event.preventDefault();
const input = this.control.control!;
console.log(input.value);
let trimmed = input.value
.replaceAll('-', '')
.replaceAll('(', '')
.replaceAll(')', '')
.replaceAll(/\s+/g, '');
if (trimmed.length > 12) {
trimmed = trimmed.substr(0, 12);
}
let numbers = [];
numbers.push(trimmed.substr(0, 3));
if (trimmed.substr(3, 2) !== '') numbers.push(trimmed.substr(3, 3));
if (trimmed.substr(6, 3) != '') numbers.push(trimmed.substr(6, 4));
input!.setValue(numbers.join('-'), { emitEvent: false });
}
}