2

I have some input fields with different validation rules set on them. But I also want to add some validation to all the fields at once, when submitting, or make submit button disabled, if there are any errors above.

However, I haven't put all my inputs inside form tag from the beginning and have kind of trouble with that right now. I am new to all of this, so can you please help me? Is there any way to solve it, without recreating all the form? :(

I've tried adding:

  <form #stepOneForm="ngForm">

  <button type="submit [disabled]="!stepOneForm.form.valid" mat-button matStepperNext>Go to next step</button>

But it didnt help...

My code looks as below:

HTML

      <!-- Name -->
      <mat-form-field class="dcp-input-field">
        <input matInput placeholder="Name" [formControl]="name" [errorStateMatcher]="matcher">
        <mat-hint>Please enter your name</mat-hint>

        <mat-error *ngIf="name.hasError('required')">
          This is <strong>required</strong> field
        </mat-error>
      </mat-form-field>

      <!-- DoB -->
      <mat-form-field class="dcp-input-field">
        <input matInput [matDatepicker]="dp" placeholder="Date of Birth" [formControl]="dob" [errorStateMatcher]="matcher">
        <mat-datepicker-toggle matSuffix [for]="dp"></mat-datepicker-toggle>
        <mat-datepicker #dp></mat-datepicker>
        <mat-hint>Please enter your date of birth</mat-hint>

        <mat-error *ngIf="dob.hasError('required')">
          This is <strong>required</strong> field
        </mat-error>
      </mat-form-field>

      <!-- PolicyNo -->
      <mat-form-field class="dcp-input-field">
        <input matInput placeholder="Policy number" [formControl]="policyNo" [errorStateMatcher]="matcher">
        <mat-hint>Please enter your Policy number</mat-hint>

        <mat-error *ngIf="policyNo.hasError('required')">
          This is <strong>required</strong> field
        </mat-error>
        <mat-error *ngIf="policyNo.hasError('minlength')">
          The value is <strong>too short</strong>
        </mat-error>
      </mat-form-field>

TS

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


  name = new FormControl("", [Validators.required]);
  dob = new FormControl("", [Validators.required]);
  policyNo = new FormControl("", [
    Validators.required,
    Validators.minLength(6)
  ]);

  matcher = new MyErrorStateMatcher();

Thank you and sorry for noob question! ;)

3
  • I've also tried to insert all my FormControls into one FormGroup, but all the single verifications have broken after that, so looks like I am doing something wrong again... Commented Nov 5, 2018 at 5:37
  • Do you want a single form on multi step of material stepper and want to disable button until the form is valid? Commented Nov 5, 2018 at 6:07
  • Actually, I want to have several forms divided by steps, and yes - I want to disable "Go to next step" button if there are some errors. So it is not necessary to set validation to overall process if all the steps are already validated. Commented Nov 5, 2018 at 6:28

1 Answer 1

8

HTML
wrap all your inputs in form tag

instead

<form #stepOneForm="ngForm">

do

<form (ngSubmit)="onSubmit()" [formGroup]="myForm"></form>

instead

<input matInput placeholder="Name" [formControl]="name" [errorStateMatcher]="matcher">

do

<input matInput placeholder="Name" formControlName="name">

that goes with all input formControlName not [formControl]

instead

<button type="submit [disabled]="!stepOneForm.form.valid" mat-button matStepperNext>Go to next step</button>

do

<button type="submit" [disabled]="myForm.invalid" mat-button matStepperNext>Go to next step</button>

--when you trying to show error msg to access to input errors validation
instead

name.hasError('required')

do

myForm.get('name').errors?.required
//or
myForm.get('name').errors['required']

both ways to check error gonna work the main different between them using safe navigation operator (?.) that's like you saying "hay angular check first if there's error (not unll or undefined) then check the type of error required, maxLength...etc" main purpose to prevent javascript from raising error cannot read property for reference safe navigation operator

or (another validation case)

*ngIf="myForm.get('name').invalid && myForm.get('name').touched"


TS

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';

@Component({
  selector: '...',
  templateUrl: '...',
  styleUrls: ['...']
})
export class myApp implements OnInit {
  myForm: FormGroup;

  ngOninit() {
    this.myForm = new FormGroup({
      'name': new FormControl(null, Validators.required),
      'policyNo': new FormControl(null, validators.minLength(5))
      // the rest of inputs with the same approach
    });
  }

  onSubmit() {
    // when submit the form do something
  }
}

you using here reactive forms not template driven each has different use make sure you use the correct way for both because you mess the reactive approach with template driven approach that what messed up everything. recommendation read Reqctive Froms Template Forms

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.