Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Username or email conditional validation

I have a forgot-password form in Angular and I had to create a conditional validation in a template driven form for input field "Username or email"
If a user enters @, it checks for email pattern, if its not, it checks for username pattern.
Now I want to redo it but I want to use a reactive approach.
I tried doing some solutions from the internet, but it didnt work.

Any advice is helpful

My Template driven HTML

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

<section class="h-100">
  <div class="container h-100">
    <div class="card forgot-password-form-card">
      <div class="card-body p-5">
        <h1 class="fs-4 card-title fw-bold mb-4">Forgot password</h1>
        <form class="form" (ngSubmit)="onSubmit(forgotPasswordForm, forgotPasswordForm.value.usernameEmail)" 
        #forgotPasswordForm="ngForm">
          <div class="mb-3">
            <p>Please enter your username or e-mail.
              <br>You will receive a link to create a new password via e-mail. <br>
            </p>
          </div>
          <div class="mb-5">
            <label for="usernameEmail">Username or e-mail address</label>
            <input id="usernameEmail" type="text" name="usernameEmail" class="form-control" ngModel required
             [pattern]="usernameEmail.value?.includes('@') ? '^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$' :
            '[a-zA-Z0-9]{3,}'" #usernameEmail="ngModel" />
            <div class="form-text text-danger" 
            *ngIf="(usernameEmail.touched || usernameEmail.dirty) && usernameEmail.errors?.['required']">
              Username or e-mail is required
            </div>
            <div class="form-text text-danger" *ngIf="(usernameEmail.touched || usernameEmail.dirty)
              && usernameEmail.errors?.['pattern']">
              Username or e-mail address is invalid
            </div>
          </div>
          <div class="d-flex align-items-center">
            <button [disabled]="!forgotPasswordForm.valid" type="submit" class="btn btn-dark
            forgot-password-button col-5 mx-auto">
              Get new password
            </button>
            <button type="button" class="btn btn-light col-5 mx-auto" appBackButton>Back</button>
          </div>
        </form>
      </div>
    </div>
</section>

My .ts file (it doesnt contain much)

import { AbstractControl, AbstractControlOptions, FormBuilder, FormControl, Validators } from '@angular/forms';
import { AppConfig } from 'src/app/_common/configs/app.config';
import { Component } from '@angular/core';

@Component({
  selector: 'app-forgot-password',
  templateUrl: './forgot-password.component.html',
  styleUrls: ['./forgot-password.component.scss'],
})
export class ForgotPasswordComponent {
  appConfig = AppConfig;
  usernameEmail = new FormControl(null, [
    (c: AbstractControl) => Validators.required(c),
    Validators.pattern()
  ]);
}

>Solution :

You can define your own custom validator function and do the checking there:

import {
  AbstractControl,
  ValidationErrors,
  ValidatorFn,
  Validators,
} from '@angular/forms';

export function emailOrUsernameValidator(usernameRe: RegExp): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const usernameValidator = Validators.pattern(usernameRe);
    return control.value?.includes('@')
      ? Validators.email(control.value)
      : usernameValidator(control);
  };
}

For the email validation, you can use the built in Validators.email, and for the username you pass the regexp that you use in the template:

usernameEmail = new FormControl(null, [
  Validators.required,
  emailOrUsernameValidator(/[a-zA-Z0-9]{3,}/)
]);

To use the reactive forms, you need to let go of ngModel. This is how the template should look:

<div class="mb-5">
  <label for="usernameEmail">Username or e-mail address</label>
  <input
    id="usernameEmail"
    type="text"
    name="usernameEmail"
    class="form-control"
    required
    [formControl]="usernameEmail"
  />
  <div class="form-text text-danger" *ngIf="usernameEmail.hasError('required')">
    Username or e-mail is required
  </div>
  <div class="form-text text-danger" *ngIf="usernameEmail.hasError('email')">
    The provided e-mail address is invalid
  </div>
  <div class="form-text text-danger" *ngIf="usernameEmail.hasError('pattern')">
    The provided username is invalid
  </div>
</div>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading