Guide to populating a dynamic dropdown menu by utilizing the formArray index when making a selection

I'm facing a situation where I need to add/remove form groups with multiple form controls.

Let's consider this scenario:

https://i.sstatic.net/N2HhL.png

The first dropdown represents the country list, the second dropdown displays states based on the selected country, and the last input control is for comments.

The issue arises when the page loads - the country dropdown fetches data from the country API by default, but the states are not loading correctly based on the selected country. Changing the country option results in all other countries' state dropdowns changing likewise.

Here's my attempt: HTML

<form [formGroup]='formName'>
              <div formArrayName="controllerArray" class="ui-g ui-g-12 ui-g-nopad " >
                <div  class="ui-g  ui-g-12 ui-g-nopad " *ngFor="let item of formName.controls.controllerArray.controls; let i=index" [formGroupName]="i">  
                  <div class="ui-md-4">                   
                    <label class="mandatory"
                  >{{ labels["STATE_OF_INCORPORATION_FILE_NUMBER"] }}
                  <span class="colon"></span>
                </label>           

                <select formControlName="select1" class="ui-inputtext" [(ngModel)]="item.controls.select1.value" (change)="changeAction($event,i)"> 
                  <option>--Select--</option>
                  <option *ngFor="let c of countryOptions" [value]="c.value">{{c.label}}</option>
                 
                </select>
              </div>
              <div class="ui-md-4">
                <label class="lbl-hidden"> State </label>
                <select formControlName="select2" class="ui-inputtext" [(ngModel)]="item.controls.select2.value"> 
                  <option>--Select--</option>
                  <option *ngFor="let b of businessStateOptions" [value]="b.value">{{b.label}}</option>
                 
                </select>
              </div>
              <div class="ui-md-3">
                <label class="lbl-hidden"> comments  </label>
                <input
                  type="text"
                  pInputText
                  class="form-control"
                  formControlName="input"    
                />
                </div>
                <div class="ui-md-1">
                  <label class="lbl-hidden"> State </label>
                  <br/>
                  <button (click)='removeInput(i)'  style="min-width: auto;"  pButton icon="fa fa-minus"></button>
                </div>
                </div>
              </div>
            </form>
            
            <button class="add-remove-btn" pButton (click)='addInput()' icon="fa fa-plus"></button>` 

Angular8 TS

import { Component, OnInit, ViewChild } from '@angular/core'
import { FormBuilder, Validators, FormArray } from '@angular/forms';

export class EntityEditComponent implements OnInit {
public countryOptions = [];

formName =this.fb.group({
    controllerArray: this.fb.array([])
  })  

ngOnInit() {    
 this.countryOptions = [{"label":"United States","value":"US"},{"label":"Canada","value":"CA"}]
}

 changeAction(e, index) { 
  if(index == 1 ) {     // Here I'm trying to change the data if country is selected CA
 let businessStateOptions = []
businessStateOptions= [{label:"Alberta",value:"CA"}]

const controlArray = <FormArray> this.formName.get('controllerArray');
    controlArray.controls[index].get('select2').setValue( businessStateOptions);
    }  
}



addInput() {(this.formName.get('controllerArray') as FormArray).push(this.fb.group({select1:'', select2:'',input:''})) }

removeInput(index) { this.formName.controls.controllerArray["controls"].splice(index,1) }

}

Expected results are,

When I change the country, only the selected country's respective states should load in the dropdown without affecting any other dropdowns.

Answer №1

Your current approach seems to be causing some confusion as you are mixing reactive forms with template driven forms. To address this, start by removing anything associated with ngModel. Next, eliminate the changeAction method. Then, replace instances of [value] with [ngValue]. In your select2 dropdown, modify how you retrieve the relevant states based on the country value from the item. Here is a suggested update:

<form [formGroup]='formName'>
              <div formArrayName="controllerArray" class="ui-g ui-g-12 ui-g-nopad " >
                <div  class="ui-g  ui-g-12 ui-g-nopad " *ngFor="let item of formName.controls.controllerArray.controls; let i=index" [formGroupName]="i">  
                  <div class="ui-md-4">                   
                    <label class="mandatory"
                  >{{ labels["STATE_OF_INCORPORATION_FILE_NUMBER"] }}
                  <span class="colon"></span>
                </label>           

                <select formControlName="select1" class="ui-inputtext"> 
                  <option>--Select--</option>
                  <option *ngFor="let c of countryOptions" [ngValue]="c.value">{{c.label}}</option>
                 
                </select>
              </div>
              <div class="ui-md-4">
                <label class="lbl-hidden"> State </label>
                <select formControlName="select2" class="ui-inputtext"> 
                  <option>--Select--</option>
                  <option *ngFor="let b of getRelevantStates(item.controls.select1.value)" [ngValue]="b.value">{{b.label}}</option>
                 
                </select>
              </div>
              <div class="ui-md-3">
                <label class="lbl-hidden"> comments  </label>
                <input
                  type="text"
                  pInputText
                  class="form-control"
                  formControlName="input" />
                </div>
                <div class="ui-md-1">
                  <label class="lbl-hidden"> State </label>
                  <br/>
                  <button (click)='removeInput(i)'  style="min-width: auto;"  pButton icon="fa fa-minus"></button>
                </div>
                </div>
              </div>
            </form>
            
            <button class="add-remove-btn" pButton (click)='addInput()' icon="fa fa-plus"></button>

To ensure the proper retrieval of relevant states based on the item in your form array, create a new method like this:

    getRelevantStates(countryId){
var states = [];
    // Retrieve states based on countryId.
return states;
    }

@Andrew: Based on the provided logic, continuous calls to getRelevantStates() may lead to issues where the corresponding states data might not load properly.

https://i.sstatic.net/AtO4A.png

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

My preference is to arrange strings in a numerical fashion

Trying to implement a sorting function with an arrow button that inverts for exam scores Struggling to get the correct sorting order The current code snippet results in [N/A, N/A, 99%, 90%, ... 20%, 100%, 10%, 0%] being sorted as [0%, 10%, 100%, 20%, ...

Leveraging jQuery's "load" functionality with a local file

Creating a website with consistent title bars across pages is a common challenge. I have been using jQuery's "load" method to load the HTML for the title bar: $("#title-bar").load("path/to/titlebar-code.html") Unfortunately, I've run into an is ...

Personalize Dropdown Menu, determining when to initiate the hide menu action

When creating a dropdown using ul and li tags, I am faced with the dilemma of determining the ideal time to hide the dropdown menu. The dropdown menu is designed to display values based on user input as they type, updating dynamically. Initially, I had se ...

I'm having trouble loading a Blender model in Three.js

I am a beginner in Blender and I have created a mesh using a bezier curve with version 2.70a. You can find the file here: When I export it to three.js format, only an empty shell is exported as shown in this link: http://pastebin.com/aVNnjE5f Exporting i ...

Bootstrap Tokenfield allows for storing values as an array rather than a string

Currently, I am utilizing the library from https://github.com/sliptree/bootstrap-tokenfield. One observation I made is that the values are being stored as a string rather than an array. Is there a method to store the values as an array instead of a string? ...

Uncovering the mystery of retrieving form values from dynamic HTML in Angular 2

As a beginner in Angular 2, I am facing challenges extracting values from Dynamic HTML. My task involves having some Form Inputs and injecting Dynamic HTML within them that contain additional inputs. I followed the example by @Rene Hamburger to create the ...

Top method for integrating configuration into a module

I'm trying to create a module called something.js that depends on a configuration, but I don't want the module itself to explicitly require the config. Additionally, I need my code editor to be able to analyze the module and provide autocomplete ...

I am experiencing difficulty with the button not responding when clicked, despite trying to implement JavaScript and the Actions syntax

Currently, I am in the process of automating form filling. After filling out the form, there is an update button that changes color instead of clicking when activated. This alteration indicates that the xpath is correctly identified. I have attempted two ...

best practices for managing a directive within another directive in Angular 6

Hello everyone! I'm having a problem with an Angular 6 directive. The directive adds a class to an element when clicked, and I want it to be removed when another element is clicked or when clicking outside the element. Please refer to the images attac ...

Create a JavaScript function to calculate a 2-tailed t distribution by adapting an already existing method

Can someone help me with implementing a two-tailed t-test in JavaScript? Resource: Student's t distribution in JavaScript for Google Spreadsheet I have taken a potential solution from the link and customized it to function outside of the form: func ...

What is the best way to revert CSS modifications when leaving a component?

I have taught myself most of what I know and I realize there may be better practices out there that could help me. Right now, I am using jQuery to adjust an element's opacity when the mouse hovers over it. However, I am struggling with making sure tha ...

The `iframe` onload event gets triggered once it has been added to a specific `

Why does the iframe onload event fire after appending it into some div, even though no source is set and no content is loaded? Here is a snippet of the code: for (var i = 0; i < items.length; i++) { addContent(element, items[i], loadData_.bind(this, ...

Having trouble adding HTML content to a parent div using jQuery and BackboneJS?

Utilizing Backbone Marionette to create a series of views, I am now faced with the task of making an AJAX call to my backend. In order to provide visual feedback to the user indicating that an action is being performed, I decided to integrate a spinner int ...

Implementing an infinite scrolling feature using Javascript within a specified div element

I'm currently working on implementing an infinite loading feature using JavaScript. I came across this helpful resource that explains how to achieve infinite scrolling without jQuery: How to do infinite scrolling with javascript only without jquery A ...

Setting a property of an object to match the value of its sibling in TypeScript

Is there a way to dynamically type an object field based on the value of its sibling? Playground link In this scenario, I have a layout type that resolves into a cell type. Cells can have a layout which should be based on the type of the field. export in ...

One function must pause and await the outcome of another function

I am developing a form that utilizes the data of the currently logged in user. The function responsible for setting the value of the form is executed before retrieving the user data. ngOnInit() { this.auth.getUserState() .subscribe( user => { ...

Please ask Java to receive a JSON parameter for converting a JSON array into a Java array

Essentially, my goal is to pass a Java String array to a JavaScript array, then pass this array via JSON to a JSP page, where I can parse it as a Java array. I attempted the following: JSONArray arr = new JSONArray(); JSONObject tmp; for(int i = 0; ...

Utilize the toggle feature to modify data displayed from the database

My webpage displays data from a database using PHP, and it works well. However, I want to add functionality that allows users to edit the displayed information by toggling between text and input form. When a user clicks on an 'Edit' button, I wan ...

Customizing date formats on HighCharts

Below is the code snippet I am currently working with: <script> $.getJSON('https://www.quandl.com/api/v3/datasets/OPEC/ORB.json?order=asc', function(json) { var hiJson = json.dataset.data.map(function(d) { return [new Date(d[0] ...

The Angular2 Router directs the user to the main Component

After configuring the Angular2 router and setting up the server (asp.net core) to redirect unknown paths to /index.html, the routing appears to be functioning properly. However, I am encountering an issue where visiting a specific URL (i.e. www.sitename.co ...