Vivek Nuna
Vivek Nuna

Reputation: 1

How to validate multiple forms in a html page?

I have a html page which has 5 in a html page. I want to disable submit button if any validation fails. but I have 2 forms always visible and 3 forms are hidden. and these 3 forms are shown based on some condition only. so there can be 2, 3, 4 or 5 forms visible.

So If I try the below code, it does not work properly, because form3,form4 and form5 are not visible.

<form class="form-horizontal" role="form" name="form1">
<form class="form-horizontal" role="form" name="form2">
<form class="form-horizontal" role="form" name="form3" *ngIf="condition1">
<form class="form-horizontal" role="form" name="form4" *ngIf="condition2">
<form class="form-horizontal" role="form" name="form5" *ngIf="condition3">

<button type="button" class="btn btn-primary" (click)="onSubmitBtnClick()" [disabled]="!form1.form.valid || !form2.form.valid || !form3.form.valid || !form4.form.valid || !form5.form.valid">Save</button>

So How I can handle this case.

Error:

Cannot read property 'form' of undefined

Upvotes: 1

Views: 364

Answers (2)

A. Tim
A. Tim

Reputation: 3196

Use angular's reactive forms + nested FormGroups: https://angular.io/guide/reactive-forms#nested-formgroups

In general, when page is loaded your form should have 3 groups (1 per "form"). Declare form as:

this.form = this.fb.group({
  subForm1: this.fb.group({
    subForm1_field1: ['', Validators.required ],
    subForm1_field2: ['', Validators.required, Validators.min(5) ],
  }),
  subForm2: this.fb.group({
    subForm2_field1: '',
    subForm2_field2: ['', Validators.required, Validators.max(10) ],
  }),
  subForm3: this.fb.group({
    subForm3_field1: '',
  })
});

So finally for submit button you can use only parent form to get validation status (it will be false if any field from any nested form group is invalid). HTML code:

<input type="checkbox" (ngModel)="onShowSubForm3()"/><label>Show Form3</label>
<form [formGroup]="form">
    <div class="form-horizontal"><!-- your inputs goes here for subForm1 --></div>
    <div class="form-horizontal"><!-- your inputs goes here for subForm2 --></div>
    <div class="form-horizontal" *ngIf="showSubForm3"><!-- your inputs goes here for subForm3 --></div>
</form>
<button type="button" (click)="submitSubForm1()" [disabled]="!form.get("subForm3").valid">Send 1</button> <!-- is disabled only if any field from `subForm3` is invalid -->
<button type="button" (click)="submitAllForms()" [disabled]="!form.valid">Send All</button> <!-- is disabled if any field is invalid -->

Code to send form/send 1 subForm:

submitAllForms(){
    let formValue = this.form.value();
    /*formValue = {
        subForm1: {
            subForm1_field1: "val1-1",
            subForm1_field2: "val1-2",
        },
        subForm2: {
            subForm2_field1: "val2-1",
            subForm2_field2: "val2-2",
        },
    };*/
    this.http.post("/url", {data: formValue});
}

submitSubForm1(){
    let subForm1Value = this.form.get["subForm1"].value;
    /*subForm1Value = {
         subForm1_field1: "val1-1",
         subForm1_field2: "val1-2",
    };*/
    this.http.post("/url", {data: subForm1Value});
}

Each time you need to show/hide new sub form - update this.form (you may want to store all fields but update Validators only).

showSubForm3: boolean = false;

onShowSubForm3(value){
    this.showSubForm3 = value;
    //THIS CODE CAN BE OPTIMIZED TO UPDATE ENTIRE `FormGroup` WITH NEW VALIDATORS
    let field = this.form.controls["subForm3.subForm3_field1"];
    if(value){
        field.setValidators(Validators.compose([Validators.required]));
    }else{
        field.setValidators(Validators.compose([]));
    }
    field.updateValueAndValidity();
}

Upvotes: 0

Tyler Jennings
Tyler Jennings

Reputation: 8911

You can accomplish this. The way I did it without triggering a bunch of change detection already checked errors is to use a singular function in my component to check form validation and whether the button should be disabled. This required me using ViewChilds for each of my forms. It looks something like this:

Component:

showForm1 = true;
showForm2 = true;
showForm3 = false;
showForm4 = false;
showForm5 = false;

@ViewChild('form1') form1: NgForm;
@ViewChild('form2') form2: NgForm;
@ViewChild('form3') form3: NgForm;
@ViewChild('form4') form4: NgForm;
@ViewChild('form5') form5: NgForm;

shouldDisable() {
    if (this.showForm1 && this.form1 && !this.form1.valid) {
      return true;
    }
    if (this.showForm2 && this.form2 && !this.form2.valid) {
      return true;
    }
    if (this.showForm3 && this.form3 && !this.form3.valid) {
      return true;
    }
    if (this.showForm4 && this.form4 && !this.form4.valid) {
      return true;
    }
    if (this.showForm5 && this.form5 && !this.form5.valid) {
      return true;
    }
    return false;
}

Template:

<form #form1="ngForm" *ngIf="showForm1"></form>
<form #form2="ngForm" *ngIf="showForm2"></form>
<form #form3="ngForm" *ngIf="showForm3"></form>
<form #form4="ngForm" *ngIf="showForm4"></form>
<form #form5="ngForm" *ngIf="showForm5"></form>


<button type="button" class="btn btn-primary" (click)="onSubmitBtnClick()" [disabled]="shouldDisable()">Save</button>

Hope that helps.

Upvotes: 1

Related Questions