Dynamic Angular select options with ngFor causing cascading changes in subsequent selects

In my Angular 5 project, I am attempting to create a set of three <select> elements using *ngFor. I came across a helpful thread on Stack Overflow that provided some guidance (check it out here). However, I've encountered an issue where the select elements are not independent - changing one affects the others, except for the third one. This is likely due to all selects sharing the same list of options. While this behavior makes sense, I want each select to be completely separate.

Below is the code snippet for looping through the 3 select elements with *ngFor:

<div class="col-sm-3" *ngFor="let groupField of selectedGroupingFields; let i = index;">
<select class="form-control col-sm-6" name="groupField{{i}}" [(ngModel)]="selectedGroupingFields[i]" (ngModelChange)="groupByFieldName($event, i)">
    <option value=""></option>
    <option [ngValue]="field.id" *ngFor="let field of columnDefinitions">{{field.name}}</option>
</select>

The collections used in this scenario are structured as follows:

selectedGroupingFields: string[] = ['', '', ''];    
columnDefinitions = [
  { id: 'title', name: 'Title'}, 
  { id: 'duration', name: 'Duration'},
  { id: 'percentComplete', name: '% Complete'},
  { id: 'start', name: 'Start'},
  { id: 'Finish', name: 'Finish'},
  { id: 'cost', name: 'Cost'},
  { id: 'effortDriven', name: 'Effort-Driven'}
];

To demonstrate the problem, I have created a function that changes the first select element when a button is clicked:

changeFirstGroupBy() {
  this.selectedGroupingFields[0] = 'title';
}

When executing this function, both the first and second select elements are affected. Curious about this unexpected behavior, I decided to manually create each select element in the HTML without using ngFor:

// Code example showing manual creation of individual select elements goes here...

Surprisingly, creating the select elements individually worked as intended, despite being structurally similar to the looped version. Moreover, changes made to the last select element also unexpectedly impact the second select. The mystery deepens...

If curious, check out this animated GIF depicting the issue:

EDIT

I attempted switching from two-way binding to one-way binding but observed no change in behavior (

[ngModel]="selectedGroupingFields[i]"
).

ANSWERED

Update: The solution described above has been successfully implemented in one of my Open Source projects, Angular-Slickgrid. Visit the GitHub repository here, and explore the functionality in action at this demo link. Many thanks for your support!

Answer №1

To tackle this issue, consider implementing a trackBy function within the usage of the ngFor directive:

<div ... *ngFor="let groupField of selectedGroupingFields; let i = index; trackBy: trackByFn">
  <select ... name="groupField{{i}}" [(ngModel)]="selectedGroupingFields[i]" (ngModelChange)="groupByFieldName($event, i)">
    <option value=""></option>
    <option [ngValue]="field.id" *ngFor="let field of columnDefinitions">{{field.name}}</option>
  </select>
</div>

In this case, ensure that the trackByFn method returns the item's index:

trackByFn(index, item) {
  return index;
}

A live demonstration can be found in this StackBlitz implementation.

Answer №2

Hello! You have implemented two-way data binding in your code.

[(ngModel)]=selectedGroupingFields[i]

If you want to achieve the desired functionality, you can modify it as shown below:

<div class="col-sm-3" *ngFor="let groupField of selectedGroupingFields; let i = index;">
 <select class="form-control col-sm-6" name="groupField{{i}}" [ngModel]="selectedGroupingFields[i]" (ngModelChange)="groupByFieldName($event, i)">
  <option value=""></option>
  <option [ngValue]="field.id" *ngFor="let field of columnDefinitions">{{field.name}} 
 </option>
</select>

You can view a working example by clicking on this link: Link

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

A guide to finding the mean in Angular by utilizing JSON information

import { Component, OnInit } from "@angular/core"; import { MarkService } from "../app/services/marks.service"; @Component({ selector: "app-root", templateUrl: "./app.component.html", styleUrls: ["./app.component.scss"] }) export class AppComp ...

When employing CDK to configure an SNS topic Policy Statement with actions limited to ["sns:*"], the CloudFormation output may display a warning message stating "Policy statement action is not within the service scope."

Encountering an issue when attempting to reference all SNS actions with * in CDK. const MyTopicPolicy = new sns.TopicPolicy(this, 'MyTopicSNSPolicy', { topics: [MyTopic], }); MyTopicPolicy.document.a ...

Is it possible to pass multiple parameters in Angular by utilizing the click() function?

Is there a method for passing parameters with click() in Angular? <a asp-action="CreateSales" (click)="CreateSales(productname='pa', price='16.5')">Some Text</a> I am still learning Angular and would appreciat ...

Trouble accessing images from database in Angular 2 with Firebase

Recently, I've integrated an image upload feature for my database using the following function: private saveFileData(upload: Upload): void { this.firebaseAuth.authState.subscribe(auth => { this.db.list(`uploads/${auth && auth.email && au ...

What is the best way to define types for an array of objects with interconnected properties?

I need to define a type for an object called root, which holds a nested array of objects called values. Each object in the array has properties named one (of any type) and all (an array of the same type as one). Below is my attempt at creating this type d ...

When parameters are added to one route, all other routes cease to function properly

After I added a parameter to one of the routes, all the other routes stopped rendering correctly (i.e., router-view is not working at all). The route /download/:id works as expected. Am I missing something in the setup? I tried leaving and removing the /do ...

Is it possible for the ionic ionViewDidEnter to differentiate between pop and setRoot operations?

I am facing an issue with my ionic 3 page where I need to refresh the data on the page only if it is entered via a navCtrl.setRoot() and not when returned to from a navCtrl.pop(). I have been using ionViewDidEnter() to identify when the page is entered, bu ...

I'm getting errors from TypeScript when trying to use pnpm - what's going

I've been facing an issue while attempting to transition from yarn to pnpm. I haven't experimented with changing the hoisting settings yet, as I'd prefer not to do so if possible. The problem lies in my lack of understanding about why this m ...

Sending template reference from one Angular component to another

I have a main grid component that includes smaller grid-item components. The majority of these grid items navigate to a specific route when clicked. However, there is one particular item that should open a modal window instead of navigating. Is there a wa ...

Displaying data in charts and tables using Angular ngrx

I am currently working on an Angular 5 app that utilizes an ngrx store to manage widgets connected to a backend using socket.io. Below is an example of how my widget objects are structured. widgets: { 1: { id: 1, type: 'datatabl ...

Trying out the results of angular services

Seeking assistance in understanding the current situation: I believe a simple tour of heroes app would be helpful in clarifying, I am looking to set up some tests using Jest to verify if the behavior of a service remains consistent over time. This is ho ...

Implementing Service Communication

I created an Angular Application using the Visual Studio Template. The structure of the application is as follows: /Clientapp ./app/app.module.shared.ts ./app/app.module.client.ts ./app/app.module.server.ts ./components/* ./services/person-data.service. ...

Incorporating a complex React (Typescript) component into an HTML page: A Step-by

I used to have an old website that was originally built with Vanilia Javascript. Now, I am in the process of converting it to React and encountering some issues. I am trying to render a compound React(Typescript) component on an HTML page, but unfortunatel ...

Using Bazel, Angular, and SocketIO Version 3 seems to be triggering an error: Uncaught TypeError - XMLHttpRequest is not recognized

Looking to integrate socket.io-client (v3) into my Angular project using Bazel for building and running. Encountering an error in the browser console with the ts_devserver: ERROR Error: Uncaught (in promise): TypeError: XMLHttpRequest is not a constructor ...

When considering Angular directives, which is more suitable for this scenario: structural or attribute?

In the process of developing an Angular 5 directive, I aim to incorporate various host views (generated from a component) into the viewContainer. However, I find myself at a crossroads as to whether I should opt for an attribute directive or a structural ...

What is the best way to find a specific string within an array of strings?

I have a list of tasks as strings: todo=[ 'Get up', 'Brush my teeth', 'Go to work', 'Play games' ]; I am attempting to compare it with this: Template: <input (input)="checkArrays($event)" /> In my ...

Submitting the form leads to an empty dynamically added row

I am currently working on a gender overview that allows you to edit, add, or delete genders using a simple table. The functionality of adding and deleting rows is already implemented. However, I am facing issues with displaying the correct web API data as ...

The error message "ng2-test-seed cannot be found - file or directory does not exist"

I've been attempting to work with an angular2 seed project, but I'm encountering some challenges. https://github.com/juliemr/ng2-test-seed When I run the command: npm run build I encounter the following error: cp: cannot stat ‘src/{index.h ...

Guide on effectively converting a table of tuples to an array of objects utility function (similar to zip) while preventing the merging of all values in typescript version 5.2.2

Almost there, but stuck on the final TS2322: Type TcolTuple[i] is not assignable to type string | number | symbol compiler error. Here's a nifty utility function called rowsToObjects() that many developers have probably come up with at some point, ...

What is the process of converting an Array that is nested within an Object?

I am facing compile errors while attempting to convert an Object containing an Array of Objects. Here is the initial structure: export interface CourseRaw { metaInfo: MetaInfoRaw; gameCode: number; gameText: string; images?: ImageRaw[]; // Having ...