8
votes

I have a bank loan application which consists of alot of input fields, some of which are hidden (the hidden fields are shown dynamically based on a set of contidions). E.g if you choose option 1, a hidden field gets shown, and some other fields are hidden. If you choose option 2, some fields gets show, other fields get hidden. In the end of the form i have a which means the button will be disabled until the whole form is valid, but my problem now is that the hidden fields also get validated so the form will never be valid. Is there a way to tell angular to not validate fields if they are hidden?

The way i hide my fields is like the example below:

<form [formGroup]="form">

<select formControlName="loanType"> 
 <option value="0">Car loan</option>
 <option value="1">Student loan</option>
</select>

<div *ngIf="loanType === 0"> 
 <input type="text" required>
</div>

<div *ngIf="loanType === 1">
 <input type="text" required>
</div>

<button type="submit" [disabled]="!form.isValid">

</form>
3
Which form syntax are you using: template-driven forms or model-driven forms? For model-driven form, I'd say hiding the field in the template is not enough, you also have to update the model (in the component class). You could use a method like AbstractControl.clearValidators() to programmatically clear the validators of a specific field. - AngularChef
(Side note: you're not just "hiding" the fields with *ngIf, you're actually removing them from the DOM.) - AngularChef
Have a look at this blog: scotch.io/tutorials/… - Yaser
@AngularFrance he is removing it with witih *ngIf, yes, so it should not affect the form in any way! Weird if it does. Interestingly enough, in Angular 1, a form is correctly .$valid, even if a required input with ng-show="false" is empty. - phil294
@Blauhirn this is a documented behavior with Angular 2's Reactive Forms and is expected, see Kara's reply to this issue: github.com/angular/angular/issues/7970 - silentsod

3 Answers

9
votes

You are using reactive form. Even the fields are hidden from user the fields are active in the from. So simply you need to disable the field from the reactive from by using following code

form.get("fieldName").disable();

In reactive form you don't require the "required" in input tag. Also add the formControlName as below.

<input formControlName="inputFieldName" type="text">

So the html file will be like

<form [formGroup]="form" novalidate>

<select formControlName="loanType"> 
 <option value="0">Car loan</option>
 <option value="1">Student loan</option>
</select>

<div *ngIf="loanType === 0"> 
 <input formControlName="inputField1" type="text">
</div>

<div *ngIf="loanType === 1">
 <input formControlName="inputField2" type="text">
</div>

<button type="submit" [disabled]="!form.isValid">

</form>

We add formControlName to 2 input fields and it is declared in ts file.

this.form = this.formBuilder.group({
    loanType: ["", [Validators.required]],
    inputField1: ["", [Validators.required]],
    inputField2: ["", [Validators.required]],
});

We can create value change listener for loanType field

this.form.get("loanType").valueChanges.subscribe((loanType) => {
    this.form.get("inputField1").disable();
    this.form.get("inputField2").disable();
    if(loanType === 1) {
         this.form.get("inputField1").enable();
    } else if (loanType === 2) {
         this.form.get("inputField2").disable();
    }
});

So when the loan type is 1 inputField1 will be enabled and when loan type is 2 inputField2 is enabled.

By this form will be valid when the fields are hidden since it is disabled.

7
votes

UPDATE:

After doing some research, i found that i need to dynamically update the formGroup by using FormGroup.addControl() and FormGroup.removeControl().

The articles i read to come to my conclusion was: https://github.com/angular/angular/issues/7970 (check Karas answer)

https://scotch.io/tutorials/how-to-implement-conditional-validation-in-angular-2-model-driven-forms

just to give an example of what my code looks like for the next man with the same problem:

if (this.loanTypeId === 1) {
   this.form.addControl('name', new FormControl("", Validators.required));
} else {
   this.form.removeControl('name')
}
0
votes

First you can create group of template basis of your option. We can use *ngIf in template to hide and show group of elements in form. Then use formBuilder to create form instance of form each time pass only object of those form controls which are enable.

Example

    <form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<label for="name">First Name:</label>
<input type="text" formControlName="fname"
placeholder="Enter name">
<br /><br />
<div *ngIf="lNameEmail1">
<label for="name">Last Name:</label>
<input type="text" formControlName="lname"
placeholder="Enter name">
<br /><br />

<label for="email">Email:</label>
<input type="email" formControlName="email"
placeholder="Enter email">
</div>
<div *ngIf="lNameEmail2">

<label for="name">Last Name2:</label>
<input type="text" formControlName="lname2"
placeholder="Enter name">

<br /><br />

<label for="email">Email2:</label>
<input type="email" formControlName="email2"
placeholder="Enter email">
</div>
<br /><br />
<button type="submit" [disabled]="!myForm.valid">Submit
</button>
<button type="submit" (click)='formGrp1()'> Form 1</button>
<button type="submit" (click)='formGrp2()'> Form 2</button>
</form> 

Angualr class

export class AppComponent implements AfterViewInit {
    public myForm: FormGroup;
    lNameEmail1 = false;
    lNameEmail2 = false;
    myFormProperty1 = {
    "fname": new FormControl("", Validators.required)
    };

    myFormProperty2 = {
    "fname": new FormControl("", Validators.required),
    "lname": new FormControl("", Validators.required),
    "email": new FormControl("")

    };
    myFormProperty3 = {
    "fname": new FormControl("", Validators.required),
    "lname2": new FormControl("", Validators.required),
    "email2": new FormControl("")

    };

    constructor(public fb: FormBuilder) {
    this.myForm = this.fb.group(this.myFormProperty1);
    }


    formGrp1(){
    alert('Form 1 enable')

    this.lNameEmail1 = true;
    this.lNameEmail2 = false;

    this.myForm = this.fb.group(this.myFormProperty2);


    this.myForm.valueChanges.subscribe(data =>
    console.log('form object ====' + JSON.stringify(data)
    )); 
    }
    formGrp2(){
    alert('Form 2 enable')

    this.lNameEmail1 = false;
    this.lNameEmail2 = true;

    this.myForm = this.fb.group(this.myFormProperty3);

    this.myForm.valueChanges.subscribe(data =>
    console.log('form object ====' + JSON.stringify(data)
    )); 

    }
    onSubmit() {
    console.log('Form submitted Value=='+ JSON.stringify(this.myForm.value));
    }



    }