简体   繁体   中英

Display input box on condition in angular reactive form

I am making angular 6 application where i am using angular reactive form.

Html:

<form [formGroup]="form">

    <h2>Click the add button below</h2>
    <button (click)="addCreds()">Add</button>
        <div formArrayName="credentials" *ngFor="let creds of form.controls.credentials?.value; let i = index">
          <div [formGroupName]="i" style="display: flex">
            <select (ngModelChange)="changeAction($event)" formControlName="action">
              <option *ngFor="let option of options" value="{{option.key}}"> {{option.value}} </option>
            </select>
            <input placeholder="Name" formControlName="name">
            <div *ngIf="showLabel">
            <input placeholder="Label" formControlName="label">
            </div>
          </div>
        </div>

    </form>

    <pre>
      {{ form ?.value | json }}
    </pre>

Ts:

  form: FormGroup;
  showLabel: boolean = false;

  options : any = [ 
    { "key" : "set", "value": "Set" },
    { "key" : "wait", "value": "Wait" },
    { "key" : "go", "value": "Go" }   
    ]

  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      credentials: this.fb.array([]),
    });
  }

  addCreds() {
    const creds = this.form.controls.credentials as FormArray;
    creds.push(this.fb.group({
      action: '',
      name: '',
      label: ''
    }));
  }

  changeAction(e) {
    if(e === "set" || e === "go") {
      this.showLabel = true;
    } else {
      this.showLabel = false;
    }
  }

Working stackblitz: https://stackblitz.com/edit/angular-form-array-example-yksojj

In this given example there will be an add button, upon clicking that button you will get a select-box with values as set,wait,go and an input called name.. Upon click over add button the same row will be added and forms each object inside array.

Also you can see an if condition inside html for label,

<div *ngIf="showLabel">
  <input placeholder="Label" formControlName="label">
</div>

The thing i am in the need was in the select box if i choose set or go then the label needs to displayed otherwise it should not be displayed for which i have written,

  changeAction(e) {
    if(e === "set" || e === "go") {
      this.showLabel = true;
    } else {
      this.showLabel = false;
    }
  }

To be clear enough If the user clicks three times add button then the dropdown and name field alone needs to be displayed for three times whereas if the user selects the value from dropdown as set or go then the label input needs to be displayed to that particular row alone where the dropdown has the value set and go .. If the selection was wait then there should not be label box for the row which has dropdown value as wait .

Kindly help me to achieve the expected result..

If you add disabled:true property to formControl it will exclude fromControl from formGroup then you can enable formControl manually

creds.push(this.fb.group({
      action: '',
      name: '',
      label: {disabled:true, value: ""}
    }));

Then enable using enable method

changeAction(e,index) {
    if(e === "set" || e === "go") {
      this.showLabel = true;     
     this.form.get('credentials').at(index).get('label').enable();

    } else {
      this.showLabel = false;
      this.form.get('credentials').at(index).get('label').disable();
    }
  }

Example: https://stackblitz.com/edit/angular-form-array-example-5buwyr

this.showLabel

The scope of this variable is your whole component. Therefore, turning it on or off will show and hide all inputs.

You need a per-row value ( creds.showLabel in your interface), or use this in your template :

*ngIf="['set','go'].includes(creds.action)"

Updated Stackblitz

By the way, this :

changeAction(e) {
    if(e === "set" || e === "go") {
      this.showLabel = true;
    } else {
      this.showLabel = false;
    }
  }

is more elegant written this way :

changeAction(e) {
    this.showLabel = ['set','go'].includes(e)
}

or this way :

changeAction(e) {
    this.showLabel = e in ['set','go']
}

Well, Jeremy's answer is pretty nice and enforces to use most of the native apis given by platform/language, however, here is a traditional approach to understand what is the actual flow and scope of objects, etc,etc...

Root Cause: The show hide field is made global to the scope of component, not at per formgroup level. So changing a single value, and using for all, will affect to all.

Solution:

  1. Use Jeremy's answer for clean coding and less error prone code.

  2. Manage an array of variable that will take care of sho/hide detail for each form group.

In the below answer, added some comments for easy understanding, and added console.log to see what exactly happening. Also, played with index i created in *ngFor and showed how you can make use of these things in future.

 import { Component } from '@angular/core'; import { FormControl, FormGroup, FormArray, FormBuilder } from '@angular/forms'; @Component({ selector: 'my-app', templateUrl: 'app.component.html', }) export class AppComponent { form: FormGroup ; showLabel = []; creds : FormArray; options : any = [ { "key" : "set", "value": "Set" }, { "key" : "wait", "value": "Wait" }, { "key" : "go", "value": "Go" } ] constructor(private fb: FormBuilder) { this.form = this.fb.group({ credentials: this.fb.array([]), }); this.creds = this.form.controls.credentials as FormArray; } addCreds() { this.creds.push(this.fb.group({ action: '', name: '', label: '' })); // every time adding new foem grp, adding lable show/hide data also. this.showLabel.push(false); } changeAction(e, i) { //every time input clikced, managing show/hide for that particular data also console.log("iii", i, e.target.value); if( e.target.value == "set" || e.target.value == "go") { this.showLabel[i] = true; } else { this.showLabel[i] = false; } } }
 <form [formGroup]="form"> <h2>Click the add button below</h2> <button (click)="addCreds()">Add</button> <div formArrayName="credentials" *ngFor="let creds of form.controls.credentials?.value; let i = index"> <div [formGroupName]="i" > <select (change)="changeAction($event, i)" formControlName="action"> <option *ngFor="let option of options" value="{{option.key}}"> {{option.value}} </option> </select> <input placeholder="Name" formControlName="name"> <div *ngIf="showLabel[i]"> <input placeholder="Label" formControlName="label"> </div> </div> </div> </form> <pre> {{ form ?.value | json }} </pre>

See live stackblitz working code

Note: Traditional is meant here.. as we every time do ie handle our problem on our own and create new problem on us to solve. It's not a tradition. :P

Please, NOT use (ngModelChange) or changeAction($event) to get the value of a control in an array -well, ngModelChange is for Template driven form, not for Reactive Form.

First change your form, create the form using a div with formArrayName="credentials" , and a inner div *ngFor="let creds of form.get('credentials') . controls

    <!--a div with formArrayName--->
    <div formArrayName="credentials" >
      <!--a div *ngFor over "controls", in this div don't forget formGroupName-->
      <div *ngFor="let creds of form.get('credentials').controls; let i = index" 
          [formGroupName]="i" style="display: flex">
          <select formControlName="action">
             <option *ngFor="let option of options" value="{{option.key}}">
               {{option.value}} 
             </option>
          </select>
          <input placeholder="Name" formControlName="name">
          <div *ngIf="??????????????">
             <input placeholder="Label" formControlName="label">
          </div>
      </div>
    </div>

Well, now the condition. To get the value of "action" you can use

form.get('credentials').at(i).value.action
//or, better
creds.value.action

So, your div becomes like

<div *ngIf="creds.value.action=='set' ||
      creds.value.action=='go'">
  <input placeholder="Label" formControlName="label">
</div>

This aproach avoid unnecesary code in your .ts.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM