chuckd
chuckd

Reputation: 14610

Custom validator not working correctly in Angular reactive form

New to Angular and trying to add a custom email validator that will go to my server and check if the email address is already in use.

But can't seem to get the error message displaying on form. Here is how I'm testing it before I attempt to hit the server.

FYI - the "emailMatchValidator()" is called but I can't get it to display any kind of error message on the form!

Maybe I should try something other than .touched!

ngOnInit() {
    this.createRegisterForm();
  }

createRegisterForm() {
  this.registerForm = this.fb.group({
    gender: ['male'],
    email: ['', [Validators.required, Validators.email]],
    username: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(10)]],
    knownAs: ['', Validators.required],
    dateOfBirth: [null, Validators.required],
    city: ['', Validators.required],
    country: ['', Validators.required],
    password: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(8)]],
    confirmPassword: ['', Validators.required]
  }, {
    validator: [this.passwordMatchValidator, this.emailMatchValidator]
  });
}

emailMatchValidator(g: FormGroup) {
  return g.get('email').value !== '[email protected]' ? null : {
    emailExists: true
  };
}
<div class="form-group">
                      <input type="email" 
                        [ngClass]="{'is-invalid': registerForm.get('email').errors && registerForm.get('email').touched}
                          || registerForm.get('email').touched && registerForm.hasError('emailExists')"
                        class="form-control" 
                        formControlName="email" 
                        placeholder="Email">
                        <div class="invalid-feedback" *ngIf="registerForm.get('email').touched && registerForm.get('email').hasError('required')">
                          Email is required
                        </div>
                        <div class="invalid-feedback" *ngIf="registerForm.get('email').touched && registerForm.get('email').hasError('email')">
                          Invalid email address
                        </div>
                        <div class="invalid-feedback" *ngIf="registerForm.get('email').touched && registerForm.get('email').hasError('emailExists')">
                            Email address already in use
                          </div>
                    </div>

Upvotes: 1

Views: 10181

Answers (1)

Akber Iqbal
Akber Iqbal

Reputation: 15041

Made some changes:

  • You had applied the validation to the complete form, i changed that to the email field only email: ['', [Validators.required, Validators.email, this.emailMatchValidator]],;

  • Added the email field value & email field status to the screen to see the validation in action

  • enter anything in the email field and move focus to get the validation in action

relevant HTML:

    <form class="form-group" [formGroup]='registerForm'>
        <input type="email" 
                        [ngClass]="{'is-invalid': registerForm.get('email').errors && registerForm.get('email').touched}
                          || registerForm.get('email').touched && registerForm.hasError('emailExists')"
                        class="form-control" 
                        formControlName="email" 
                        placeholder="Email">
                        <div class="invalid-feedback" *ngIf="registerForm.get('email').touched && registerForm.get('email').hasError('required')">
                          Email is required
                        </div>
                        <div class="invalid-feedback" *ngIf="registerForm.get('email').touched && registerForm.get('email').hasError('email')">
                          Invalid email address
                        </div>
                        <div class="invalid-feedback" *ngIf="registerForm.get('email').touched && registerForm.get('email').hasError('emailExists')">
                            Email address already in use
                          </div>
                    </form>

<hr/>
                    <b>email value:</b> {{registerForm.controls.email.value}} <br/>
                    <b>email status:</b> {{registerForm.controls.email.status}}

relevant TS:

import { Component } from '@angular/core';
import { FormBuilder, Validators, FormGroup, AbstractControl } from '@angular/forms'

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name = 'Angular';
  constructor(private fb: FormBuilder) { }
  registerForm;

  ngOnInit() {
    this.createRegisterForm();
    console.log(this.registerForm);
  }

  createRegisterForm() {
    this.registerForm = this.fb.group({
      gender: ['male'],
      email: ['', [Validators.required, Validators.email, this.emailMatchValidator]],
      username: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(10)]],
      knownAs: ['', Validators.required],
      dateOfBirth: [null, Validators.required],
      city: ['', Validators.required],
      country: ['', Validators.required],
      password: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(8)]],
      confirmPassword: ['', Validators.required]
    }
      /*, {
          validator: [this.passwordMatchValidator, this.emailMatchValidator]
        }
        */
    );
  }

  passwordMatchValidator() {
    /* some implementation */
  }

  emailMatchValidator(control: AbstractControl) {
    if (control.value !== '[email protected]') {
      return false;
    } else {
      return { emailExists: true };
    }
  }

}

working stackblitz here

Upvotes: 2

Related Questions