Angular Reactive Form - Dynamic building of array values (hide and show values based on the iteration)

367 views Asked by At

Sample code - Stackblitz

I need to populate the values based on the below Format JSON,

    "days": [
      {
        "date": "2020-09-21T09:00:04.206+00:00",
        "nodes": [
          {
            "type": "leg",
            "from": "airport",
            "to": "oshiage station",
            "cost": 1170
          },
         {
            "type": "activity",
            "category": "food",
            "cost": 200,
            "location": "ramen place"
          }
          {
            "type": "activity",
            "category": "food",
            "cost": 2000,
            "location": "soup curry restaurant",
          },      
        ]
      }
    ]

The form also has separate buttons such as 'Add Leg' and 'Add activity' in the form.

I was not able to control the nodes for both types separately so I decided to hide the div class of the leg attribute when an activity is added and hide activity when leg is added and finally remove the null values before sending to the server so I would get it in the respected JSON Format.

However, I'm not able to achieve the show and hide behavior for the iterative forms. When activity button is clicked, activity form is populated for the 1st iteration, and when I want to add the leg values after clicking the button, the leg values which was hidden in the previous iteration is also populated.

Is there any way I could hide and show values based on the iteration?

Sample .ts file:

  form: FormGroup;
  bubbleActivity:any;
  bubbleTravel:any;
 addTravel(ix){
    this.bubbleTravel = true;
    const control = (<FormArray>this.form.controls['days']).at(ix).get('nodes') as FormArray;
    control.push(
        this.fb.group({
            type: 'leg',
            from: '',
            to: '',
            cost:'',
            category: null,
            costActivity: null,
            location:null,
          })
    )
  }
addActivity(ix) {
    this.bubbleActivity = true;
    const control = (<FormArray>this.form.controls['days']).at(ix).get('nodes') as FormArray;
    control.push
    (
        this.fb.group({
            type: 'activity',
            from: null,
            to: null,
            cost:null,
            category: '',
            costActivity: '',
            location:'',
          })
    )
  }

Can find elaborate code here

Expectation: If I'm adding activity for the first two iteration, and then I click the leg button I want the leg to be displayed only on 3rd iteration and not to display on the first two iteration as well. And proceeding to it, if I'm clicking the activity button it should be 4th iteration after leg. Basically trying to achieve seperate controls on same formArray.

Please suggest if you find any other alternative to this.

1

There are 1 answers

0
Eldar On BEST ANSWER

Alternatively, you can separate your form into 2 pieces. Wrap your form pieces with divs that are conditionally rendered. Use type as the condition provider like below :

<div *ngIf="Y.value.type === 'leg'">
 <!-- leg  form controls here -->
</div>
<div *ngIf="Y.value.type === 'activity'">
 <!-- activity form controls here -->
</div>

And don't initialize form with empty values.

Stackblitz