Search code examples
javascriptangularvalidationemailangular-reactive-forms

Email Validation with required overlaps in Angular Reactive Forms


Using Angular Reactive Forms for validation of Email.

I added Validators Required and Validators Email but Its displaying both as shown in below image. I just want one Error to be displayed at a time.

enter image description here

HTML Code :

<form [formGroup]="NamFomNgs">

    <label>Email : 
        <input type="email" name="MylHtm" formControlName="MylNgs">
    </label><br>
        <div class="ErrMsgCls" *ngIf="(NamFomNgs.controls['MylNgs'].touched || NamFomNgs.controls['MylNgs'].dirty) && 
            !NamFomNgs.controls['MylNgs'].valid">
            <span *ngIf="NamFomNgs.controls['MylNgs'].errors.required">This field is required</span>
            <span *ngIf="NamFomNgs.controls['MylNgs'].errors.email">Enter valid email</span>
        </div><br>

    <button [disabled]="!NamFomNgs.valid">Submit</button>
</form>

Typescript Code :

NamFomNgs:FormGroup;

constructor(private NavPkjVaj: ActivatedRoute, private HtpCncMgrVaj: HttpClient,private FomNgsPkjVaj: FormBuilder)
{
    this.NamFomNgs = FomNgsPkjVaj.group(
        {
            MylNgs:[null,Validators.compose([
                Validators.required,
                Validators.email ])]
        });
}

I feel it's a bug in angular form.


Solution

  • You can create common component to display validation message:

    custom-validation-with-error-message

    HTML:

    <div *ngIf="errorMessage !== null">
        {{errorMessage}}
    </div>
    

    constrol-message.component.ts:

    import { OnInit } from '@angular/core';
    import { Component, Input } from '@angular/core';
    import { FormGroup, FormControl, AbstractControl } from '@angular/forms';
    
    import { CustomValidationService } from '../custom-validation.service'
    
    
    export class ControlMessageComponent implements OnInit {
    
      ngOnInit() {
    
      }
      @Input() control: FormControl;
    
      constructor() { }
    
        /**
         * This method is use to return validation errors
         */
      get errorMessage() {
        for (let propertyName in this.control.errors) {
          if (this.control.errors.hasOwnProperty(propertyName) && this.control.touched) {
            return CustomValidationService.getValidatorErrorMessage(this.getName(this.control), propertyName, this.control.errors[propertyName]);
          }
          if (this.control.valueChanges) {
            return CustomValidationService.showValidatorErrorMessage(propertyName, this.control.errors[propertyName])
          }
        }
        return null;
      }
    
        /**
         * This method used to find the control name
         * @param control - AbstractControl
         */
      private getName(control: AbstractControl): string | null {
        let group = <FormGroup>control.parent;
    
        if (!group) {
          return null;
        }
        let name: string;
        Object.keys(group.controls).forEach(key => {
          let childControl = group.get(key);
          if (childControl !== control) {
            return;
          }
          name = key;
        });
        return name;
      }
    }