angulartypescriptangular-reactive-formsngx-international-phone-number

Angular - How to validate maxlength in ngx-intl-tel-input


I am using the ngx-intl-tel-input package in my Angular-12 project multistep. I have this code:

Component:

import {
  SearchCountryField,
  CountryISO,
  PhoneNumberFormat
} from 'ngx-intl-tel-input';

export class SignupCompanyComponent implements OnInit {
  isLinear = true;
  isLoading = false;
  companySetupForm!: FormGroup;
  companyForm!: FormGroup;
  idForm!: FormGroup;
  SearchCountryField = SearchCountryField;
  CountryISO = CountryISO;
  preferredCountries: CountryISO[] = [CountryISO.UnitedStates, CountryISO.UnitedKingdom];

  changePreferredCountries() {
    this.preferredCountries = [CountryISO.India, CountryISO.Canada];
  }

  ngOnInit() {
    this.companyForm = this.fb.group({
      companyName: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(100)]],
      mobileNumber: ['', [Validators.required, Validators.maxLength(15)]],
    }, {
      updateOn: "blur"
    });
    this.idForm = this.fb.group({
      registrationNumber: ['', [Validators.required, Validators.maxLength(100)]],
    });
  }

  get fc() {
    return this.companyForm.controls;
  };
  get fi() {
    return this.idForm.controls;
  };

  onSubmit() {
    this.isSubmitted = true;

    const formCompanyData = this.companyForm.getRawValue();
    const formIdData = this.idForm.getRawValue();

    const data = {
      companyName: formCompanyData.companyName,
      mobileNumber: formCompanyData.mobileNumber,
      registrationNumber: formCompanyData.registrationNumber,
    };

    this.spinnerService.show();
    const header = {
      'Content-Type': 'application/json'
    };

    this.isLoading = true;
    return this.api.post('signup', data, header)
      .pipe(first())
      .subscribe(
        data => {
          this.tokenHandler(data);
        });
  }
}

HTML:

<mat-horizontal-stepper [linear]="isLinear" #stepper labelPosition="bottom">
  <mat-step [stepControl]="companyForm">
    <form [formGroup]="companyForm">
      <ng-template matStepLabel matStepperIcon="phone">Company Info</ng-template>

      <div class="col-12 col-md-4">
        <div class="form-group">
          <label for="mobileNumber">Mobile Number:<span style="color:red;">*</span></label>
          <div class="input-group mb-4">
            <ngx-intl-tel-input [cssClass]="'form-control mb-4'" [preferredCountries]="preferredCountries" [enableAutoCountrySelect]="false" [enablePlaceholder]="true" [searchCountryFlag]="true" [searchCountryField]="[SearchCountryField.Iso2, SearchCountryField.Name]"
              [selectFirstCountry]="false" [selectedCountryISO]="CountryISO.India" [maxlength]="15" [phoneValidation]="true" [separateDialCode]="true" name="mobileNumber" formControlName="mobileNumber">
            </ngx-intl-tel-input>
          </div>
        </div>
        <div *ngIf="fc.mobileNumber.touched && fc.mobileNumber.invalid">
          <div *ngIf="fc.mobileNumber.hasError('required')">
            <div class="text-danger">
              Mobile Number is required!
            </div>
          </div>
          <div *ngIf="fc.mobileNumber.hasError('maxlength')">
            <div class="text-danger">
              Mobile Number cannot be more than 15 characters!
            </div>
          </div>
        </div>
      </div>
      <div class="col-12 col-md-8">
        <div class="form-group">
          <label for="name">Company Name:<span style="color:red;">*</span></label>}
          <input type="text" formControlName="companyName" placeholder="Company Name" class="form-control" required/>
        </div>
        <div *ngIf="fc.companyName.touched && fc.companyName.invalid">
          <div *ngIf="fc.companyName.hasError('required')">
            <div class="text-danger">
              Company Name is required!
            </div>
          </div>
          <div *ngIf="fc.companyName.hasError('minlength')">
            <div class="text-danger">
              Company Name cannot be less than 3 characters!
            </div>
          </div>
          <div *ngIf="fc.companyName.hasError('maxlength')">
            <div class="text-danger">
              Company Name cannot be more than 100 characters!
            </div>
          </div>
        </div>
      </div>
      <div class="card-footer">
        <button mat-raised-button color="primary" matStepperNext [disabled]="companyForm.status != 'VALID'">Next</button>
      </div>
    </form>
  </mat-step>
  <mat-step [stepControl]="idForm">
    <form [formGroup]="idForm">
      <ng-template matStepLabel>Company ID</ng-template>
      <div class="col-12 col-md-12">
        <div class="form-group">
          <label for="registration_number">Registration Number:<span style="color:red;">*</span></label>
          <input type="text" formControlName="registrationNumber" placeholder="Registration Number" class="form-control" required/>
        </div>
        <div *ngIf="fi.registrationNumber.touched && fi.registrationNumber.invalid">
          <div *ngIf="fi.registrationNumber.hasError('required')">
            <div class="text-danger">
              Company Reg. No. is required!
            </div>
          </div>
          <div *ngIf="fi.registrationNumber.hasError('maxlength')">
            <div class="text-danger">
              Company Reg. No. cannot be more than 100 characters!
            </div>
          </div>
        </div>
      </div>
      <div class="card-footer">
        <button mat-raised-button color="black" matStepperPrevious>Back</button> &nbsp;
        <button mat-raised-button color="success" [disabled]="isLoading" type="submit" (click)="onSubmit()">
                        <span *ngIf="isLoading" class="spinner-border spinner-border-sm mr-1"></span>
                          Submit
                      </button> &nbsp;
        <button mat-raised-button color="warn" (click)="stepper.reset()">Reset</button>
      </div>
  </mat-step>
</mat-horizontal-stepper>

When the user enters data, I expect input validation. But I have these two (2) issues on the mobileNumber in the ngx-intl-tel-input:

  1. It allows the users to enter more than 15 maxlength.

  2. Whenever the maxlength is greater than 15, it disables the Next button without indicating the error and this brings confusion.

How do I resolve these?

Thanks.


Solution

  • Look like maxLength validation is not supported by ngx-mat-intl-tel-input.

    Instead,

    You have to use validatePhoneNumber to determine whether the inputted text is a valid phone number. As Official documentation (Refer to Example section) provides the example:

    If you want to show the sample number for the country selected or errors , use mat-hint anf mat-error as

    <mat-error *ngIf="f.form.controls['phone']?.errors?.validatePhoneNumber">Invalid Number</mat-error>
    

    And the Next button is disabled is due to the inputted phone number doesn't fulfill the phone number format for the selected country.


    SOLUTION

    The HTML for validatePhoneNumber validation should be as below:

    signup-company.component.html

    <div *ngIf="fc.mobileNumber.touched && fc.mobileNumber.invalid">
      ...
      <div *ngIf="fc.mobileNumber.hasError('validatePhoneNumber')">
        <div class="text-danger">
          Invalid Phone Number!
        </div>
      </div>
    </div>
    

    And remember to remove Validators.maxLength(100) from mobileNumber field as it is no longer needed.

    signup-company.component.ts

    this.companyForm = this.fb.group(
    {
      companyName: [
      '',
      [
        Validators.required,
        Validators.minLength(3),
        Validators.maxLength(100)
      ]],
      mobileNumber: ['', [
        Validators.required
      ]]
    },
    {
      updateOn: 'blur'
    });
    

    Sample solution on StackBlitz