Home > Back-end >  Username or email conditional validation
Username or email conditional validation

Time:04-11

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

<section >
  <div >
    <div >
      <div >
        <h1 >Forgot password</h1>
        <form  (ngSubmit)="onSubmit(forgotPasswordForm, forgotPasswordForm.value.usernameEmail)" 
        #forgotPasswordForm="ngForm">
          <div >
            <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 >
            <label for="usernameEmail">Username or e-mail address</label>
            <input id="usernameEmail" type="text" name="usernameEmail"  ngModel required
             [pattern]="usernameEmail.value?.includes('@') ? '^[a-z0-9._% -] @[a-z0-9.-] \\.[a-z]{2,4}$' :
            '[a-zA-Z0-9]{3,}'" #usernameEmail="ngModel" />
            <div  
            *ngIf="(usernameEmail.touched || usernameEmail.dirty) && usernameEmail.errors?.['required']">
              Username or e-mail is required
            </div>
            <div  *ngIf="(usernameEmail.touched || usernameEmail.dirty)
              && usernameEmail.errors?.['pattern']">
              Username or e-mail address is invalid
            </div>
          </div>
          <div >
            <button [disabled]="!forgotPasswordForm.valid" type="submit" >
              Get new password
            </button>
            <button type="button"  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()
  ]);
}

CodePudding user response:

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)
      : 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 >
  <label for="usernameEmail">Username or e-mail address</label>
  <input
    id="usernameEmail"
    type="text"
    name="usernameEmail"
    
    required
    [formControl]="usernameEmail"
  />
  <div  *ngIf="usernameEmail.hasError('required')">
    Username or e-mail is required
  </div>
  <div  *ngIf="usernameEmail.hasError('email')">
    The provided e-mail address is invalid
  </div>
  <div  *ngIf="usernameEmail.hasError('pattern')">
    The provided username is invalid
  </div>
</div>
  • Related