Is there a way to apply the same technique to a dynamic select option in Angular?

My array is dynamic and has an onChange method in the select option. The issue arises when I add a new array and select the new option, as it causes the first array to reset. Here's a snippet of my array structure:

  <ng-container formGroupName="envelopeRequest">
    <button (click)='initDocument()'>Add Document</button>
    <ng-container formArrayName="documents">
      <ng-container
        *ngFor="let control of documents.controls; let comIndex=index"
      >
        <ng-container [formGroupName]="comIndex">
          <div class="row justify-content-start mb-3">
            <div class="col-md-1">
              {{comIndex}}
              <input
                type="hidden"
                id="fname"
                name="fname"
                formControlName="documentId"
              />
              <label for="formFile" class="col-form-label">File:</label>
            </div>
            <div class="col-md-6">
              <input
                class="form-control"
                type="file"
                id="file"
                name="file"
                formControlName="name"
              />
            </div>
          </div>
          <ng-container formArrayName="documentFields">
            <ng-container
              *ngFor="let skillIndex of documentFieldsIndexes(comIndex);"
            >
              <div class="row mb-3">
                <label class="col-sm-1 col-form-label">Category:</label>
                <div class="col-md-2">
                  <ng-container [formGroupName]="skillIndex">
                    <select id="" class="form-select" formControlName="value"  (change)="changeCategoryList($event)">
                      <option selected>Select</option>
                      <option *ngFor="let c of categoryList">
                        {{c.name}}
                      </option>
                    </select>
                  </ng-container>
                </div>

                <label class="col-auto col-form-label">Sub-Category:</label>
                <div class="col-md-2">
                  <ng-container [formGroupName]="skillIndex + 1">
                    <select id="" class="form-select" formControlName="value" (change)="changeSubCategoryList($event)">
                      <option selected>Select</option>
                      <option *ngFor="let s of subCategoryList">{{s.name}}</option>
                    </select>
                  </ng-container>
                </div>
                <label class="col-auto col-form-label">List:</label>
                <div class="col-md-2">
                  <ng-container [formGroupName]="skillIndex + 2">
                    <select id="" class="form-select" formControlName="value">
                      <option selected>Select</option>
                      <option *ngFor="let name of typeList">{{name}}</option>
                    </select>
                  </ng-container>
                </div>
              </div>
            </ng-container>
          </ng-container>
        </ng-container>
      </ng-container>
    </ng-container>
  </ng-container>

I suspect that both select options are using the same method, leading to this issue. Below is a section of my TypeScript code showcasing the methods:

 changeCategoryList(category: any) {
    this.subCategoryList = this.categoryList.find(
      (cat: any) => cat.name == category.target.value
    ).subCategoryList;
  }

  changeSubCategoryList(subList: any) {
    this.typeList = this.categoryList
      .find((cat: any) => cat.name == this.selectedCategoryList)
      .subCategoryList.find(
        (stat: any) => stat.name == subList.target.value
      ).typeList;
  }

Lastly, I'm wondering if it's possible to have an index on a method. For further reference and viewing the full code, please check out the link to the StackBlitz below:

StackBlitz

Answer №1

Based on the structure of your HTML code, it appears that you are utilizing the subCategoryList instance to share select options for documentSubCategory across multiple FormGroups within the documents FormArray.

To prevent data overwriting when selecting documentSubCategory in different FormGroups, it is recommended to create and use a distinct instance for each FormGroup.

You can achieve this by using the comIndex to organize the data selection list under specific FormGroups. The subCategoryList will be structured as a multi-dimensional array containing data corresponding to sub-categories based on the order defined by the comIndex. This approach mirrors the process used for documentType selection.

subCategoryList: Array<any[]> = [];
typeList: Array<any[]> = [];

changeCategoryList(category: any, comIndex: number) {
  this.subCategoryList[comIndex] = this.categoryList.find(
    (cat: any) => cat.name == category.target.value
  ).subCategoryList;
}

changeSubCategoryList(subList: any, comIndex: number) {
  let selectedCategory = this.documentFields(comIndex).get('0')?.get('value')?.value;
      
  this.typeList[comIndex] = this.categoryList
    .find((cat: any) => cat.name == selectedCategory)
    .subCategoryList.find(
      (stat: any) => stat.name == subList.target.value
    ).typeList;      
}

When adding a new document, ensure that you include an empty array in both the subCategoryList and typeList arrays.

newDocument() {
  this.subCategoryList.push([]);
  this.typeList.push([]);

  return this.fb.group({
    name: new FormControl(''),
    documentId: new FormControl(''),
    documentFields: this.fb.array([]),
  });
}

In your HTML, remember to pass the comIndex parameter to the changeCategoryList and changeSubCategoryList methods. Utilize subCategoryList[comIndex] and typeList[comIndex] to access the respective select options.

<select id="" class="form-select" formControlName="value"  (change)="changeCategoryList($event, comIndex)">
  <option selected>Select</option>
  <option *ngFor="let c of categoryList">
    {{c.name}}
  </option>
</select>

<select id="" class="form-select" formControlName="value" (change)="changeSubCategoryList($event, comIndex)">
  <option selected>Select</option>
  <option *ngFor="let s of subCategoryList[comIndex]">{{s.name}}</option>
</select>

...

<select id="" class="form-select" formControlName="value">
  <option selected>Select</option>
  <option *ngFor="let name of typeList[comIndex]">{{name}}</option>
</select>

Check out the Demo on StackBlitz

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

Group data by date in a hashmap

In my Spring Boot backend, I am managing apps and games with a Rating Object that saves rating history in a HashMap. // Number of history by day @ElementCollection(fetch = FetchType.EAGER) private Map<String, Integer> ratingHistory = new HashMap<& ...

Expanding and collapsing all nodes in Angular Material 6.0.1 Tree by default

Exploring the Angular Material Tree in my current project and wondering if it can be set to open by default. Also, is there a way to conveniently expand/collapse all nodes at once, maybe with the help of a button? Link to Angular Material Tree documentat ...

What is the proper way to inject a defined namespace using Angular's Dependency Injection?

I'm attempting to include the npm url node_module into my Angular service. Instead of just importing it like this: import * as url from 'url'; and using it in my class like so: url.format(); //using it I'd prefer to inject it, as I ...

The service has terminated unexpectedly because of signal: Ended prematurely: 9

I'm encountering the error 'Service exited due to signal: Killed: 9' and am unable to launch my app. I've come across information suggesting that this may be caused by memory leaks or a lengthy startup time for the app. In all honesty, ...

Rollup faces challenges when trying to bundle source code alongside Bazel and Typescript

I am attempting to create a bundle using rollup, typescript, and bazel environment. I am having trouble importing relative paths. Typescript builds correctly but rollup is unable to bundle the source. WORKSPACE # WORKSPACE workspace( name = "WORK ...

The variable 'selectedvalue' is being accessed before it has been initialized

I'm currently working on sharing the date between components using BehaviorSubject, but I'm encountering an error in the process. public data = new BehaviorSubject<any>(this.selectedValue); public sharedData = this.data.asObservable(); sele ...

Guide on incorporating text input areas into specific positions within a string

Looking for a way to replace specific words in a string with input fields to enter actual values? For example... Dear Mr. [Father_name], your son/daughter [name] did not attend class today. This is what I want it to look like... Dear Mr. Shankar, your ...

Why isn't my JavaScript variable visible in the HTML code?

I am currently facing an issue with my Angular app where I am trying to display a JavaScript variable in HTML. The variable successfully shows up in an older part of my application, but it fails to do so in the new section. Below is the functional code sn ...

What is the process of converting the new syntax of SomeFunction() to TypeScript?

When I try to convert a basic JS file to TS while having implicit "any" disabled, I encounter the following error: Error TS7009: When attempting to create a new expression without a constructor signature, it implicitly defaults to an 'any' typ ...

Evaluating string combinations in JavaScript using valid comparisons

After choosing values on the screen, two variables store their value. var uval = '100'; var eval = '5'; There are 2 combinations with values: let combination1= 'u:100;e:1,4,5,10' let combination2 = 'u:1000;e:120,400,500, ...

How to implement SVG in React with the image source as a parameter?

I've been working on a React component in NextJS that displays an image inside a hexagon. The issue I'm facing is that when I try to use multiple instances of this component with different images in the HexagonWall, all hexagons end up displaying ...

The factory class is responsible for generating objects without specifying their type

I manage a factory that specializes in facilitating dependency injection. Here's an example of what it looks like: import SomeImportantObject from "./SomeImportantObject" import DataInterface from "./DataInterface" class NoodleFactory { this.depen ...

What is the approach of Angular 2 in managing attributes formatted in camelCase?

Recently, I've been dedicating my time to a personal project centered around web components. In this endeavor, I have been exploring the development of my own data binding library. Progress has been made in creating key functionalities akin to those f ...

Ways to programmatically include routes with components sourced from a dynamically loaded module

One of my Angular components is dynamic and module-based: The module file is named dynamic-component.module.ts @NgModule({ imports: [ DynamicComponentRoutingModule, FormsModule, CommonModule, FormsModule, ], declarations: [ ...

Ways to implement es6 in TypeScript alongside react, webpack, and babel

Being new to front-end development, I have found that following a simple tutorial can quickly help me start tackling problems in this field. One issue I've encountered is with ES5, which lacks some of the tools that are important to me, like key-value ...

Angular continually monitors changes for dom-to-image and generates countless renders

I am trying to implement a feature in my Angular 4 application where child-components render wallpapers for themselves using dom-to-image-more. The issue arises when I try to dynamically render these child-components using *ngFor. The parent component h ...

Demonstrating the transformation of child elements into parent elements through angular 6 ngFor

I have a JSON array dataset where each object may contain nested arrays. In order to display the inner nested array elements as part of the parent array using Angular's NgFor, I need to format the input like this: [{ 'id': 1, 'tit ...

Transforming button click from EventEmitter to RXJS observable

This is the functionality of the component utilizing EventEmitter: import { Component, Output, EventEmitter } from "@angular/core"; @Component({ selector: "app-my-component", template: ` <button (click)="clickEvent($event)& ...

There is an issue with the type candidate in the Notion API, resulting in

In this instance, the troublesome code causing issues is displayed below: import {Client, LogLevel} from "@notionhq/client"; const notion = new Client({ auth: process.env.NOTION_TOKEN, logLevel: process.env.NODE_ENV !== 'product ...

Typescript error encountered in customized PipeLine class

I am currently developing a web scraping application using Puppeteer. In this project, I aim to create a PipeLine class that will take the current instance of the page and expose an add method. This add method should accept an array of functions with the t ...