Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Material Form Validation

If the fields of my FormGroup are model-bound, ala [(ngModel)], and become populated on page load, e.g. because of a service, my Submit Button, which is guarded as [disabled]="biodataForm.status !== 'VALID'", does not become disabled. If the form comes up blank and I fill it in normally, the guard passes when the form is correctly filled out. If the same exact values are populated through the data-binding, the biodataForm.status value remains INVALID until I change the value of every field.

My feeling is that the form should recognize it has valid content after the data-bindings are populated, and its status should change from INVALID to VALID as a result... what's going wrong here?

My form markup looks like this:

  <form class="form" name="biodataForm" [formGroup]="biodataForm">
    <mat-form-field class="full-width">
      <input matInput placeholder="First Name" 
        required
        [(ngModel)]="_memberdata.firstname"
        [formControl]="firstnameFormControl">
      <mat-error *ngIf="firstnameFormControl.invalid">{{getRequiredErrorMessage('firstname')}}</mat-error>        
    </mat-form-field>
    <mat-form-field class="full-width">
      <input matInput placeholder="Last Name" 
        required
        [(ngModel)]="_memberdata.lastname"
        [formControl]="lastnameFormControl">
      <mat-error *ngIf="lastnameFormControl.invalid">{{getRequiredErrorMessage('lastname')}}</mat-error>                
    </mat-form-field>
    <mat-form-field class="full-width"
      hintLabel="Note: We'll send you an email with a link to click to prove it's you">
      <input matInput placeholder="Email" 
        required
        [(value)]="_memberdata.email"
        [formControl]="emailFormControl">
      <mat-error *ngIf="emailFormControl.invalid">{{getEmailErrorMessage()}}</mat-error>        
    </mat-form-field>    
    <mat-form-field class="full-width">
      <input matInput placeholder="Phone" type="tel" 
        [(value)]="_memberdata.phone"
        required
        [formControl]="phoneFormControl">
      <mat-error *ngIf="phoneFormControl.invalid">{{getPhoneErrorMessage()}}</mat-error>
    </mat-form-field>        
    <button mat-raised-button color="primary" 
      class="submit-button"
      [disabled]="biodataForm.status !== 'VALID'"
      (click)="handleNext()">Next Step</button>
  </form>

```

My Angular component surrounding this form looks like this (details omitted for clarity, full source is here):

export class WelcomeComponent {
  emailFormControl = new FormControl('', [
    Validators.required,
    Validators.email,
  ]);
  firstnameFormControl = new FormControl('', [Validators.required]);
  lastnameFormControl = new FormControl('', [Validators.required]);
  phoneFormControl = new FormControl('', [
    Validators.required,
    Validators.pattern(/(\(?[0-9]{3}\)?-?\s?[0-9]{3}-?[0-9]{4})/)
  ]);
  // addressFormControl = new FormControl('', [Validators.required]);
  biodataForm: FormGroup = new FormGroup({
    email: this.emailFormControl,
    firstname: this.firstnameFormControl,
    lastname: this.lastnameFormControl,
    phone: this.phoneFormControl
    // address: this.addressFormControl
  });

  getEmailErrorMessage() {
    return this.emailFormControl.hasError('required') ? 'You must enter a value' :
      this.emailFormControl.hasError('email') ? 'Not a valid email' : '';
  }
  getPhoneErrorMessage() {
    return this.phoneFormControl.hasError('required') ? 'You must enter a value' :
      this.phoneFormControl.hasError('pattern') ? 'Format must be (xxx) xxx-xxxx' : '';
  }
  getRequiredErrorMessage(field) {
    return this.biodataForm.get(field).hasError('required') ? 'You must enter a value' : '';
  }

  constructor(
    public _memberdata: MemberDataService,
    private _api: ApiService,
    private _router: Router,
    private _snackBar: MatSnackBar) { }

  handleNext() {
     // ... handle button click
  }
}

```

like image 485
vicatcu Avatar asked Apr 13 '18 22:04

vicatcu


People also ask

What is form validation in Angular?

Angular uses directives to match these attributes with validator functions in the framework. Every time the value of a form control changes, Angular runs validation and generates either a list of validation errors that results in an INVALID status, or null, which results in a VALID status.

What is AbstractControl in Angular?

It provides some of the shared behavior that all controls and groups of controls have, like running validators, calculating status, and resetting state. It also defines the properties that are shared between all sub-classes, like value , valid , and dirty . It shouldn't be instantiated directly.

What is Matinput?

Matinput is an Angular directive that primarily allows input and text area elements to work with a form field. With this, you can display placeholders perfectly, add custom error messages, a clear button, specify the maximum length of the text or add prefixes and suffixes for a seamless user experience.


1 Answers

The form itself can be checked with valid and invalid. The below should work:

[disabled]="biodataForm.invalid"

Info on the Angular form group can be found at: https://angular.io/api/forms/FormGroup

In addition, the email and phone inputs...you are using [(value)]...change those to [(ngModel)] and it should work the way you expect.

like image 88
jdgower Avatar answered Nov 15 '22 03:11

jdgower