Angular 7 Material Design Generic Validation Implementation












-1















Please feel free to redirect me if something similar has been asked on SO before (I couldn't find anything similar to my problem)



I am very comfortable with AngularJS but pretty new on Angular/(Angular7). I normally use directives for generic validations which short cuts the development.
With angular material design, I tried to implement form validation but what I have noticed in the examples that we are creating a FormControl for each and every field that we want to validate or a FormGroup as a list of FormControl in it but still I have to define a new validator for each and every field I want to validate. I am pretty sure there should be an easier way and thats what I am looking for.



For instance, I have created a shared validator as following:



import { FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core';

export class ZenValidator implements ErrorStateMatcher {
public ZenFormGroup: FormGroup;
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
}

getEmailValidator() {
return new FormControl('', [
Validators.required,
Validators.email
]);
}

getNameValidator() {
return new FormControl('', [
Validators.required
]);
}

getFormValidators() {
return this.ZenFormGroup = new FormGroup({
name: new FormControl('', [
Validators.required,
Validators.maxLength(60)
]),
dateOfBirth: new FormControl(new Date()),
address: new FormControl('', [
Validators.required,
Validators.maxLength(100)
]),
email: new FormControl('', [
Validators.required,
Validators.email
])
});
}
}


And based on the example I found, I am using it as following in my html:



 <div class="col-lg-3 col-md-4 no-left-padding">
<mat-form-field [floatLabel]="options.value.floatLabel">
<mat-label>First Name</mat-label>
<input matInput placeholder="enter a first name"
[(ngModel)]="user.Firstname"
[formControl]="nameValidator"
[errorStateMatcher]="zenValidator">
<mat-error *ngIf="nameValidator.hasError('required')">
This field is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<div class="col-lg-3 col-md-4 no-left-padding">
<mat-form-field [floatLabel]="options.value.floatLabel">
<mat-label>Last Name</mat-label>
<input matInput placeholder="enter a last name"
[(ngModel)]="user.Lastname"
[formControl]="nameValidator"
[errorStateMatcher]="zenValidator">
<mat-error *ngIf="nameValidator.hasError('required')">
This field is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>
<div class="col-lg-3 col-md-4 no-left-padding">
<mat-form-field [floatLabel]="options.value.floatLabel">
<mat-label>Email Address</mat-label>
<input matInput placeholder="enter an email address" [(ngModel)]="user.EmailAddress"
[formControl]="emailValidator"
[errorStateMatcher]="zenValidator">
<mat-error *ngIf="emailValidator.hasError('email') && !emailValidator.hasError('required')">
Please enter a valid email address
</mat-error>
<mat-error *ngIf="emailValidator.hasError('required')">
Email is <strong>required</strong>
</mat-error>
</mat-form-field>
</div>


And in my component, Im using it like below:



import { ZenValidator } from '@app/modules/shared/helpers/zen-validator';
// all other imports etc... here
// component decorator etc... here
export class UserEditComponent implements OnInit, AfterViewInit {

emailValidator;
nameValidator;
user = new User();
options: FormGroup;
constructor(fb: FormBuilder
, public zenValidator: ZenValidator
, private cdr: ChangeDetectorRef
) {
this.options = fb.group({
hideRequired: false,
floatLabel: 'auto',
});

this.emailValidator = zenValidator.getEmailValidator();
this.nameValidator = zenValidator.getNameValidator();

}

ngAfterViewInit() {

}
ngOnInit() {

}
}


I do not want to create a bunch of validators for each fields on the pages. What I want to do is, create a generic text box validator for instance which checks the maxlength and required. Thats it. Then date validator, etc.
But if I try to use the same validator that I created as "nameValidator" and try to use it on both FirstName and LastName fields, it just shows the error message for both input fields if one of them is not valid for instance (since they both use the same [formControl]='nameValidator'). So that is why I was thinking, "So what? Now I have to create a separate validator for each field? No way!" and wanted to ask you guys. Thanks



PS: I have no issue to use if there is any other (better) 3rd party approach to use that you can suggest for validations.










share|improve this question





























    -1















    Please feel free to redirect me if something similar has been asked on SO before (I couldn't find anything similar to my problem)



    I am very comfortable with AngularJS but pretty new on Angular/(Angular7). I normally use directives for generic validations which short cuts the development.
    With angular material design, I tried to implement form validation but what I have noticed in the examples that we are creating a FormControl for each and every field that we want to validate or a FormGroup as a list of FormControl in it but still I have to define a new validator for each and every field I want to validate. I am pretty sure there should be an easier way and thats what I am looking for.



    For instance, I have created a shared validator as following:



    import { FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
    import { ErrorStateMatcher } from '@angular/material/core';

    export class ZenValidator implements ErrorStateMatcher {
    public ZenFormGroup: FormGroup;
    isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const isSubmitted = form && form.submitted;
    return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
    }

    getEmailValidator() {
    return new FormControl('', [
    Validators.required,
    Validators.email
    ]);
    }

    getNameValidator() {
    return new FormControl('', [
    Validators.required
    ]);
    }

    getFormValidators() {
    return this.ZenFormGroup = new FormGroup({
    name: new FormControl('', [
    Validators.required,
    Validators.maxLength(60)
    ]),
    dateOfBirth: new FormControl(new Date()),
    address: new FormControl('', [
    Validators.required,
    Validators.maxLength(100)
    ]),
    email: new FormControl('', [
    Validators.required,
    Validators.email
    ])
    });
    }
    }


    And based on the example I found, I am using it as following in my html:



     <div class="col-lg-3 col-md-4 no-left-padding">
    <mat-form-field [floatLabel]="options.value.floatLabel">
    <mat-label>First Name</mat-label>
    <input matInput placeholder="enter a first name"
    [(ngModel)]="user.Firstname"
    [formControl]="nameValidator"
    [errorStateMatcher]="zenValidator">
    <mat-error *ngIf="nameValidator.hasError('required')">
    This field is <strong>required</strong>
    </mat-error>
    </mat-form-field>
    </div>
    <div class="col-lg-3 col-md-4 no-left-padding">
    <mat-form-field [floatLabel]="options.value.floatLabel">
    <mat-label>Last Name</mat-label>
    <input matInput placeholder="enter a last name"
    [(ngModel)]="user.Lastname"
    [formControl]="nameValidator"
    [errorStateMatcher]="zenValidator">
    <mat-error *ngIf="nameValidator.hasError('required')">
    This field is <strong>required</strong>
    </mat-error>
    </mat-form-field>
    </div>
    <div class="col-lg-3 col-md-4 no-left-padding">
    <mat-form-field [floatLabel]="options.value.floatLabel">
    <mat-label>Email Address</mat-label>
    <input matInput placeholder="enter an email address" [(ngModel)]="user.EmailAddress"
    [formControl]="emailValidator"
    [errorStateMatcher]="zenValidator">
    <mat-error *ngIf="emailValidator.hasError('email') && !emailValidator.hasError('required')">
    Please enter a valid email address
    </mat-error>
    <mat-error *ngIf="emailValidator.hasError('required')">
    Email is <strong>required</strong>
    </mat-error>
    </mat-form-field>
    </div>


    And in my component, Im using it like below:



    import { ZenValidator } from '@app/modules/shared/helpers/zen-validator';
    // all other imports etc... here
    // component decorator etc... here
    export class UserEditComponent implements OnInit, AfterViewInit {

    emailValidator;
    nameValidator;
    user = new User();
    options: FormGroup;
    constructor(fb: FormBuilder
    , public zenValidator: ZenValidator
    , private cdr: ChangeDetectorRef
    ) {
    this.options = fb.group({
    hideRequired: false,
    floatLabel: 'auto',
    });

    this.emailValidator = zenValidator.getEmailValidator();
    this.nameValidator = zenValidator.getNameValidator();

    }

    ngAfterViewInit() {

    }
    ngOnInit() {

    }
    }


    I do not want to create a bunch of validators for each fields on the pages. What I want to do is, create a generic text box validator for instance which checks the maxlength and required. Thats it. Then date validator, etc.
    But if I try to use the same validator that I created as "nameValidator" and try to use it on both FirstName and LastName fields, it just shows the error message for both input fields if one of them is not valid for instance (since they both use the same [formControl]='nameValidator'). So that is why I was thinking, "So what? Now I have to create a separate validator for each field? No way!" and wanted to ask you guys. Thanks



    PS: I have no issue to use if there is any other (better) 3rd party approach to use that you can suggest for validations.










    share|improve this question



























      -1












      -1








      -1








      Please feel free to redirect me if something similar has been asked on SO before (I couldn't find anything similar to my problem)



      I am very comfortable with AngularJS but pretty new on Angular/(Angular7). I normally use directives for generic validations which short cuts the development.
      With angular material design, I tried to implement form validation but what I have noticed in the examples that we are creating a FormControl for each and every field that we want to validate or a FormGroup as a list of FormControl in it but still I have to define a new validator for each and every field I want to validate. I am pretty sure there should be an easier way and thats what I am looking for.



      For instance, I have created a shared validator as following:



      import { FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
      import { ErrorStateMatcher } from '@angular/material/core';

      export class ZenValidator implements ErrorStateMatcher {
      public ZenFormGroup: FormGroup;
      isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
      const isSubmitted = form && form.submitted;
      return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
      }

      getEmailValidator() {
      return new FormControl('', [
      Validators.required,
      Validators.email
      ]);
      }

      getNameValidator() {
      return new FormControl('', [
      Validators.required
      ]);
      }

      getFormValidators() {
      return this.ZenFormGroup = new FormGroup({
      name: new FormControl('', [
      Validators.required,
      Validators.maxLength(60)
      ]),
      dateOfBirth: new FormControl(new Date()),
      address: new FormControl('', [
      Validators.required,
      Validators.maxLength(100)
      ]),
      email: new FormControl('', [
      Validators.required,
      Validators.email
      ])
      });
      }
      }


      And based on the example I found, I am using it as following in my html:



       <div class="col-lg-3 col-md-4 no-left-padding">
      <mat-form-field [floatLabel]="options.value.floatLabel">
      <mat-label>First Name</mat-label>
      <input matInput placeholder="enter a first name"
      [(ngModel)]="user.Firstname"
      [formControl]="nameValidator"
      [errorStateMatcher]="zenValidator">
      <mat-error *ngIf="nameValidator.hasError('required')">
      This field is <strong>required</strong>
      </mat-error>
      </mat-form-field>
      </div>
      <div class="col-lg-3 col-md-4 no-left-padding">
      <mat-form-field [floatLabel]="options.value.floatLabel">
      <mat-label>Last Name</mat-label>
      <input matInput placeholder="enter a last name"
      [(ngModel)]="user.Lastname"
      [formControl]="nameValidator"
      [errorStateMatcher]="zenValidator">
      <mat-error *ngIf="nameValidator.hasError('required')">
      This field is <strong>required</strong>
      </mat-error>
      </mat-form-field>
      </div>
      <div class="col-lg-3 col-md-4 no-left-padding">
      <mat-form-field [floatLabel]="options.value.floatLabel">
      <mat-label>Email Address</mat-label>
      <input matInput placeholder="enter an email address" [(ngModel)]="user.EmailAddress"
      [formControl]="emailValidator"
      [errorStateMatcher]="zenValidator">
      <mat-error *ngIf="emailValidator.hasError('email') && !emailValidator.hasError('required')">
      Please enter a valid email address
      </mat-error>
      <mat-error *ngIf="emailValidator.hasError('required')">
      Email is <strong>required</strong>
      </mat-error>
      </mat-form-field>
      </div>


      And in my component, Im using it like below:



      import { ZenValidator } from '@app/modules/shared/helpers/zen-validator';
      // all other imports etc... here
      // component decorator etc... here
      export class UserEditComponent implements OnInit, AfterViewInit {

      emailValidator;
      nameValidator;
      user = new User();
      options: FormGroup;
      constructor(fb: FormBuilder
      , public zenValidator: ZenValidator
      , private cdr: ChangeDetectorRef
      ) {
      this.options = fb.group({
      hideRequired: false,
      floatLabel: 'auto',
      });

      this.emailValidator = zenValidator.getEmailValidator();
      this.nameValidator = zenValidator.getNameValidator();

      }

      ngAfterViewInit() {

      }
      ngOnInit() {

      }
      }


      I do not want to create a bunch of validators for each fields on the pages. What I want to do is, create a generic text box validator for instance which checks the maxlength and required. Thats it. Then date validator, etc.
      But if I try to use the same validator that I created as "nameValidator" and try to use it on both FirstName and LastName fields, it just shows the error message for both input fields if one of them is not valid for instance (since they both use the same [formControl]='nameValidator'). So that is why I was thinking, "So what? Now I have to create a separate validator for each field? No way!" and wanted to ask you guys. Thanks



      PS: I have no issue to use if there is any other (better) 3rd party approach to use that you can suggest for validations.










      share|improve this question
















      Please feel free to redirect me if something similar has been asked on SO before (I couldn't find anything similar to my problem)



      I am very comfortable with AngularJS but pretty new on Angular/(Angular7). I normally use directives for generic validations which short cuts the development.
      With angular material design, I tried to implement form validation but what I have noticed in the examples that we are creating a FormControl for each and every field that we want to validate or a FormGroup as a list of FormControl in it but still I have to define a new validator for each and every field I want to validate. I am pretty sure there should be an easier way and thats what I am looking for.



      For instance, I have created a shared validator as following:



      import { FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
      import { ErrorStateMatcher } from '@angular/material/core';

      export class ZenValidator implements ErrorStateMatcher {
      public ZenFormGroup: FormGroup;
      isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
      const isSubmitted = form && form.submitted;
      return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
      }

      getEmailValidator() {
      return new FormControl('', [
      Validators.required,
      Validators.email
      ]);
      }

      getNameValidator() {
      return new FormControl('', [
      Validators.required
      ]);
      }

      getFormValidators() {
      return this.ZenFormGroup = new FormGroup({
      name: new FormControl('', [
      Validators.required,
      Validators.maxLength(60)
      ]),
      dateOfBirth: new FormControl(new Date()),
      address: new FormControl('', [
      Validators.required,
      Validators.maxLength(100)
      ]),
      email: new FormControl('', [
      Validators.required,
      Validators.email
      ])
      });
      }
      }


      And based on the example I found, I am using it as following in my html:



       <div class="col-lg-3 col-md-4 no-left-padding">
      <mat-form-field [floatLabel]="options.value.floatLabel">
      <mat-label>First Name</mat-label>
      <input matInput placeholder="enter a first name"
      [(ngModel)]="user.Firstname"
      [formControl]="nameValidator"
      [errorStateMatcher]="zenValidator">
      <mat-error *ngIf="nameValidator.hasError('required')">
      This field is <strong>required</strong>
      </mat-error>
      </mat-form-field>
      </div>
      <div class="col-lg-3 col-md-4 no-left-padding">
      <mat-form-field [floatLabel]="options.value.floatLabel">
      <mat-label>Last Name</mat-label>
      <input matInput placeholder="enter a last name"
      [(ngModel)]="user.Lastname"
      [formControl]="nameValidator"
      [errorStateMatcher]="zenValidator">
      <mat-error *ngIf="nameValidator.hasError('required')">
      This field is <strong>required</strong>
      </mat-error>
      </mat-form-field>
      </div>
      <div class="col-lg-3 col-md-4 no-left-padding">
      <mat-form-field [floatLabel]="options.value.floatLabel">
      <mat-label>Email Address</mat-label>
      <input matInput placeholder="enter an email address" [(ngModel)]="user.EmailAddress"
      [formControl]="emailValidator"
      [errorStateMatcher]="zenValidator">
      <mat-error *ngIf="emailValidator.hasError('email') && !emailValidator.hasError('required')">
      Please enter a valid email address
      </mat-error>
      <mat-error *ngIf="emailValidator.hasError('required')">
      Email is <strong>required</strong>
      </mat-error>
      </mat-form-field>
      </div>


      And in my component, Im using it like below:



      import { ZenValidator } from '@app/modules/shared/helpers/zen-validator';
      // all other imports etc... here
      // component decorator etc... here
      export class UserEditComponent implements OnInit, AfterViewInit {

      emailValidator;
      nameValidator;
      user = new User();
      options: FormGroup;
      constructor(fb: FormBuilder
      , public zenValidator: ZenValidator
      , private cdr: ChangeDetectorRef
      ) {
      this.options = fb.group({
      hideRequired: false,
      floatLabel: 'auto',
      });

      this.emailValidator = zenValidator.getEmailValidator();
      this.nameValidator = zenValidator.getNameValidator();

      }

      ngAfterViewInit() {

      }
      ngOnInit() {

      }
      }


      I do not want to create a bunch of validators for each fields on the pages. What I want to do is, create a generic text box validator for instance which checks the maxlength and required. Thats it. Then date validator, etc.
      But if I try to use the same validator that I created as "nameValidator" and try to use it on both FirstName and LastName fields, it just shows the error message for both input fields if one of them is not valid for instance (since they both use the same [formControl]='nameValidator'). So that is why I was thinking, "So what? Now I have to create a separate validator for each field? No way!" and wanted to ask you guys. Thanks



      PS: I have no issue to use if there is any other (better) 3rd party approach to use that you can suggest for validations.







      angular validation material-design angular-material-7






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 19 at 21:45







      curiousBoy

















      asked Jan 19 at 20:53









      curiousBoycuriousBoy

      2,59322333




      2,59322333
























          0






          active

          oldest

          votes











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54271305%2fangular-7-material-design-generic-validation-implementation%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          0






          active

          oldest

          votes








          0






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54271305%2fangular-7-material-design-generic-validation-implementation%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Liquibase includeAll doesn't find base path

          How to use setInterval in EJS file?

          Petrus Granier-Deferre