Build a phone field
TelixonPhoneInput is a directive for an <input> bound to a form
control. The user types into the input and sees a formatted number. The form control receives the
same number in E.164, or null while the number is incomplete.
The control
Section titled “The control”import { Component } from '@angular/core';import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';import { TelixonPhoneInput, type ValidationError } from '@telixon/angular';
@Component({ selector: 'app-contact', imports: [ReactiveFormsModule, TelixonPhoneInput], template: ` <input type="tel" autocomplete="tel" #phone="telixonPhoneInput" [telixonPhoneInput]="{ mode: 'international', defaultRegion: 'US' }" [formControl]="control" [placeholder]="phone.state()?.placeholder ?? ''" [attr.aria-invalid]="control.touched && control.invalid ? true : null" aria-describedby="phone-error" />
@if (control.touched) { @if (control.errors?.['telixonPhone']; as fault) { <p id="phone-error">{{ message(fault) }}</p> } @else if (control.errors?.['required']) { <p id="phone-error">Phone number is required.</p> } } `,})export class Contact { readonly control = new FormControl<string | null>(null, Validators.required);
message(fault: ValidationError): string { switch (fault.kind) { case 'TOO_SHORT': case 'POSSIBLE_LOCAL_ONLY': return 'This number is too short.'; case 'TOO_LONG': return 'This number is too long.'; default: return 'This number does not exist.'; } }}Once the engine has loaded, the input shows the calling code of the default region, 1 . Typing
4155550132 turns it into 1 415-555-0132. Once the last digit is typed, the control holds
+14155550132. The options are the ones createPhoneInput takes.
Show the errors
Section titled “Show the errors”An invalid number puts a ValidationError under the
telixonPhone key of control.errors. A partial number keeps the control’s value at null, which
makes required report at the same time. The template therefore checks telixonPhone before
required. The message method turns each fault kind into text.
The input’s aria-describedby points at the message element. aria-invalid follows
control.touched && control.invalid. Inside a Material form field, matInput sets both on its
own.
The placeholder
Section titled “The placeholder”The binding [placeholder]="phone.state()?.placeholder ?? ''" puts an example number on the input.
The example belongs to the field’s region and follows the field’s format:
| Options | Placeholder |
|---|---|
{ mode: 'national', defaultRegion: 'US' } |
(201) 555-0123 |
{ mode: 'international', defaultRegion: 'US' } |
1 201-555-0123 |
with display: { callingCodeInInput: false } |
201-555-0123 |
{ mode: 'national', defaultRegion: 'GB' } |
07400 123456 |
Template-driven forms
Section titled “Template-driven forms”The directive works with ngModel the same way:
<input name="phone" [telixonPhoneInput]="{ mode: 'international' }" [(ngModel)]="phone" #model="ngModel" />phone receives +14155550132 once the number is valid and null at any other time.
model.errors carries telixonPhone.
Add a region picker puts a region picker next to the field.