title: Angular Material Form Validation
body: <p>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 <code>[disabled]="biodataForm.status !== 'VALID'"</code>, 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 <em>change</em> the value of every field.</p>
  
  <p>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?</p>
  
  <p>My form markup looks like this:</p>
  
  <pre class="lang-html prettyprint-override"><code>  &lt;form class="form" name="biodataForm" [formGroup]="biodataForm"&gt;
      &lt;mat-form-field class="full-width"&gt;
        &lt;input matInput placeholder="First Name" 
          required
          [(ngModel)]="_memberdata.firstname"
          [formControl]="firstnameFormControl"&gt;
        &lt;mat-error *ngIf="firstnameFormControl.invalid"&gt;{{getRequiredErrorMessage('firstname')}}&lt;/mat-error&gt;        
      &lt;/mat-form-field&gt;
      &lt;mat-form-field class="full-width"&gt;
        &lt;input matInput placeholder="Last Name" 
          required
          [(ngModel)]="_memberdata.lastname"
          [formControl]="lastnameFormControl"&gt;
        &lt;mat-error *ngIf="lastnameFormControl.invalid"&gt;{{getRequiredErrorMessage('lastname')}}&lt;/mat-error&gt;                
      &lt;/mat-form-field&gt;
      &lt;mat-form-field class="full-width"
        hintLabel="Note: We'll send you an email with a link to click to prove it's you"&gt;
        &lt;input matInput placeholder="Email" 
          required
          [(value)]="_memberdata.email"
          [formControl]="emailFormControl"&gt;
        &lt;mat-error *ngIf="emailFormControl.invalid"&gt;{{getEmailErrorMessage()}}&lt;/mat-error&gt;        
      &lt;/mat-form-field&gt;    
      &lt;mat-form-field class="full-width"&gt;
        &lt;input matInput placeholder="Phone" type="tel" 
          [(value)]="_memberdata.phone"
          required
          [formControl]="phoneFormControl"&gt;
        &lt;mat-error *ngIf="phoneFormControl.invalid"&gt;{{getPhoneErrorMessage()}}&lt;/mat-error&gt;
      &lt;/mat-form-field&gt;        
      &lt;button mat-raised-button color="primary" 
        class="submit-button"
        [disabled]="biodataForm.status !== 'VALID'"
        (click)="handleNext()"&gt;Next Step&lt;/button&gt;
    &lt;/form&gt;
  </code></pre>
  
  <p>```</p>
  
  <p>My Angular component surrounding this form looks like this (details omitted for clarity, full source is <a href="https://github.com/ithacagenerator/IGOnBoard/tree/master/AngularApp/src/app/welcome" rel="noreferrer">here</a>):</p>
  
  <pre class="lang-ts prettyprint-override"><code>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
    }
  }
  </code></pre>
  
  <p>```</p>