Phone Directive causing validation issues in Angular when attempting to paste a value into the control for formatting

In our current project, we are utilizing Angular 17 in conjunction with Reactive forms. A custom directive has been implemented to format the output to the US phone number format `111-222-3333`. However, an issue has arisen where when a number is copied into the field, the field becomes formatted but the validator still detects it as invalid.

Here is the HTML Code:

<input matInput phoneFormatterDirective placeholder="Enter Phone" formControlName="phone" class="inputEntry">

And the Typescript Code:

phone: new FormControl(null, [Validators.pattern('^[0-9]{3}-[0-9]{3}-[0-9]{4}$')])

Below is the 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;

    // Formatting logic here
  }
}

When attempting to paste a number like `(555) 123-1234`, it gets converted to `555-123-1234` but still shows as invalid. A workaround is deleting a character and re-entering it manually, which is a peculiar behavior.

https://i.sstatic.net/4ad48YzL.png

Answer №1

At the moment, the formatted value is being set to the value of HtmlInputElement, but it is not updating the state of the form control.

To address this issue, I recommend fetching and setting the value from/to NgControl to properly 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 });
  }
}

Check out the live demo on StackBlitz

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Obtain the precise Discriminated conditional unions type in the iterator function with Typescript

export type FILTER_META = | { type: 'string'; key: string; filters: { id: string; label?: string }[]; } | { type: 'time'; key: string; filters: { min: string; max: string }[]; } | { ...

Executing the serve command in an Angular project necessitates a project definition, which unfortunately could not be located

An issue has arisen with the application I developed (angular2 nodejs). Upon attempting to open it, I encountered the following error message: The serve command needs to be executed within an Angular project, however a project definition could not be lo ...

The Angular module does not have any exported member named 'ButtonFillMode'

Encountering an error message stating '"@progress/kendo-angular-buttons"' has no exported member 'ButtonFillMode'. when utilizing the Kendo Editor toolbar module. Despite having installed all necessary dependencies for the Edi ...

Integration of Mocha with WebStorm

WebStorm offers a useful feature that adds a small arrow next to describe() and it() keywords when writing tests with Mocha, allowing for easy manual execution. However, there is a challenge: I require additional setup before each test, leading me to use ...

Encountering an error with the iconv-lite package in TypeScript code

I recently added the "iconv-lite" package to my project, imported the module, and attempted to use the decode method. However, I encountered the following error: TypeError: Cannot read properties of undefined (reading 'decode') Interestingly, ...

When utilizing custom ngDoBootstrap and createCustomElement in Angular, the router fails to recognize the URL being used

WHEN I implement a custom ngDoBootstrap function instead of the default bootstrap: [AppComponent] like shown below: @NgModule({ imports: [ BrowserModule, FormsModule, AppRoutingModule ], declarations: [ AppComponent, HelloComponent ], exports: ...

Tips for converting a string array constant into a union type

I have a string array that I want to use to create a new type where the properties correspond to the elements in the array. There are different types of arrays and I have a function that generates different output types based on the input array. const RG ...

How to send variables to a function when a value changes in TypeScript and Angular

As someone who is new to Angular and HTML, I am seeking assistance with the following code snippet: <mat-form-field> <mat-select (valueChange)="changeStatus(list.name, card.name)"> <mat-option *ngFor="let i of lists"> {{i.name}} ...

Exploring the Power of TS Enum Flags within Angular 2+ Templates

Can TypeScript's Enum Flags be used in Angular templates? I'm having trouble using the "&" bitwise operator. Is it possible or not? Just want to confirm. export enum Flags { Virgin = 0, Loading = 1 << 0, Loaded = 1 <&l ...

Issue: Incompatibility between React and TypeScript leading to an error message - "No

When I try to map through an array in my code, I encounter a significant error as shown below: // Home.tsx render() { const { inputs, outputs, expectedOutputs } = this.state; return ( <ContentContainer> {inputs.map((inpu ...

Error: Call stack size limit reached in Template Literal Type

I encountered an error that says: ERROR in RangeError: Maximum call stack size exceeded at getResolvedBaseConstraint (/project/node_modules/typescript/lib/typescript.js:53262:43) at getBaseConstraintOfType (/project/node_modules/typescript/lib/type ...

Encountering an error stating "ngbCollapse" is not a recognized property of "div" after relocating components to a sub module

Error compiler.js:215 Uncaught Error: Template parse errors: Can't bind to 'ngbCollapse' since it isn't a known property of 'div'. ("][ngbCollapse]="isHidden" In the process of organizing my code, I encountered an issue ...

encountering issues with configuring TypeScript LSP in NeoVim with the use of the lazy package manager

Encountered an error in nvim when opening a .ts file. Using mason, mason-lspconfig, and nvim-lspconfig for lsp setup. Lua language lsp is functioning properly, but facing errors with ts files as shown in the screenshot below: https://i.stack.imgur.com/gYM ...

When using AngularJS (ng1), TypeScript, and PhoneGap on iOS, the <select> element may display the incorrect option, even though the model contains the correct one

framework: Angular 1 platform: iOS On iOS, using a <select> element will cause the view to display the next <option> in the list once one is chosen, while the model will contain the correct value. If the <select> element is pressed aga ...

Problem with synchronizing an Angular 2 application and the Angular 2 router

Currently dealing with a complex problem related to asynchronicity within an angular 2 application. The main issue arises when trying to reload information from the backend upon app refresh in the user's browser (such as F5/refresh). The setback occu ...

Setting an optional property to null is not permitted

In my model class, I have defined an optional property as follows: export class Workflow { constructor( public id: number, public started: Date, public documentId: number, public document: Document, public status: WorkflowStatus, ...

Compile time error due to TypeScript enumeration equality issue

Currently, I am developing a system to manage user roles within my website using TypeScript enumeration. This will allow me to restrict access to certain parts of the site based on the user's role. The primary challenge I am facing is comparing the u ...

JavaScript placeholder-type expression

Hey there, I am a C++ developer who is venturing into the world of JavaScript. While exploring JavaScript syntax, I stumbled upon something that resembles templates in C++. For example, while going through RxJs tutorials, I came across this line of code: ...

The type '{} is not compatible with the type 'IProps'

In my current project, I am utilizing React alongside Formik and TypeScript. The code snippet below demonstrates my usage of the withFormik Higher Order Component (HOC) in my forms: import React from 'react'; // Libraries import........ import { ...

An error in TypeScript has occurred, stating that the type 'IterableIterator<any>' is neither an array type nor a string type

Hey there! I'm currently working on an Angular project and encountering an error in my VS Code. I'm a bit stuck on how to fix it. Type 'IterableIterator<any>' is not an array type or a string type. Use compiler option '- ...