Utilizing Angular 4 Typescript to create cascading drop-downs within a table

As a newcomer to Angular, I am in the process of building my first application using Angular 4 and TypeScript.

I would like to implement Cascading dropdowns within a table using Angular 4.

Currently, I am facing an issue where changing the dropdown selection in one row affects all other rows as well.

My goal is to have the second level dropdown in each row update only when the corresponding first level dropdown is changed.

I have some ideas on how to tackle this, but I believe there might be a more elegant solution using Angular methods. Any guidance on achieving this functionality using Angular would be greatly appreciated.

Below is a snippet of the TypeScript code:

import { Component, OnInit, EventEmitter } from '@angular/core';
import { Category } from '../model/Category';
import { SubCategory } from '../model/subCategory';
import { Partner } from '../model/partner';
import { GetdataService } from '../../../../Server/api/Getdata.service';
import { Router } from '@angular/router';

@Component({
  templateUrl: 'UploadFile.component.html'
})
export class UploadFileComponent implements OnInit {
  AllCategoryList: Category[] = [];
  AllSubCategoryList: SubCategory[] = [];
  constructor(private _datatask: GetdataService, private _router: Router) { }

  onChangeCategory(deviceValue) {         
    if (deviceValue > 0) {
      this._datatask.getAllSubCategory(deviceValue).subscribe(
        (data: SubCategory[]) => {
          this.AllSubCategoryList = data;
        }
      );
      console.log("from component: " + deviceValue);
    }
    else
      {
        //clear dropdown...
        this.AllSubCategoryList= [];        
      }
  }

  ngOnInit() {
    this._datatask.getAllCategory().subscribe(
      (data: Category[]) => {
        this.AllCategoryList = data;
      }
    );

    this._datatask.getAllPartner().subscribe(
      (data: Partner[]) => {
        this.AllPartnerList = data;
      }
    );
  }  
}

And here is a snippet of the HTML code:

<div>
  <table width="100%" border="1">
    <thead>     
      <th>Category</th>
      <th>SubCategory</th>
      <th>Partner</th>
    </thead>
    <tbody *ngFor="let transaction of transactions">
      <tr>       
        <td>
          <select style="Width:100px;" (change)="onChangeCategory($event.target.value)" >
            <option value=0>--Select--</option>
                <option  value="{{item.ID}}"  *ngFor="let item of AllCategoryList" [ngValue]="item.ID" >{{item.Category}}</option>
            </select>
        </td>
        <td>
          <select style="Width:100px;">
            <option value=0>--Select--</option>
                 <option  *ngFor="let item of AllSubCategoryList" [ngValue]="item.ID" >{{item.SubCategory}}</option> 
            </select>
        </td>
        <td>
          <select style="Width:100px;">
            <option value=0>--Select--</option>
                <option  *ngFor="let item of AllPartnerList" [ngValue]="item.ID" >{{item.PartnerName}}</option>
            </select>
        </td>
      </tr>
    </tbody>
  </table>
</div>

Any assistance or advice on this matter would be highly appreciated.

Answer №1

It seems that the issue lies in the requirement for an array of states, as mentioned in the provided plunker. This same solution can likely be applied to your original code.

Adjustment made to list-component.ts file:

export class CountryListComponent {

  states: State[] = [[] as State[],[] as State[],[] as State[]] 

  onSelect(value,index) {
    this.states[index] = this._dataService.getStates().
      filter((item)=> item.countryid == value);
  }
}

Edit in list-component.html file:

  • Update: following a discussion on this thread with @GünterZöchbauer :
  • Switched from using (change) to (ngModelChange)

<select [(ngModel)]="selectedCountry[number].id"
    (ngModelChange)="onSelect($event, number)">

Revised Plunker

Answer №2

I encountered a similar issue and was able to resolve it by creating a custom pipe.

To create the filter in an external file, you can follow these steps:

mycustomfilter.ts

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'myCustomFilter',
    pure: false
})
export class myCustomFilterPipe implements PipeTransform {

  transform(items: any[], field : string, value): any[] {
    if (!items) return [];
    if (!value || value.length === 0) return items;
    return items.filter(it =>
    it[field] === value);
  }
}

Include the declarations in your app module like this:

@NgModule({
  imports: [ BrowserModule, FormsModule ],
  declarations: [ App, myCustomFilterPipe],
  bootstrap: [ App ]
})

In your item-order.component.ts file, define your categoryList and itemList arrays:

categoryList=[{id:1,name:'Office Stationery'},
              {id:2,name:'Grocery'}
        ];
itemList=[
         {id:1,name:'Pen',categoryID:1},
         {id:2,name:'A4 Peper',categoryID:1},
         {id:3,name:'Oil',categoryID:2},
         {id:4,name:'Sugar',categoryID:2}
    ];

Within your item-order.component.html file, use the custom filter in the template:

<tr *ngFor="let order of o.controls; let i = index" [formGroup]="order" class="form-row">
              
<td>
<select class="form-control" formControlName="ItemCategoryID">
<option value="">Select</option>
<option *ngFor="let s of categoryList" [ngValue]="s.id">{{s.name}}</option>
</select>
</td>
<td>
<select class="form-control" formControlName="ItemID">
<option value="">Select</option>
<option *ngFor="let s of itemList | myCustomFilter : 'categoryID' : order.value.ItemCategoryID" [ngValue]="s.id">{{s.name}}</option>
</select>
</td>
</tr>

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

AngularJS is throwing an error stating that the URL ID is undefined

I am developing an application that utilizes angularjs with codeigniter as the backend. Within my URL, I have http://localhost/submit/1234, with 1234 serving as the ID. Within my angularjs setup: var singlepost = angular.module('singlepost', [ ...

Utilizing ion-list to showcase the subcategories of the chosen element

I'm currently developing an app that involves displaying a list of items. When a user selects an item, they are redirected to another page where a new set of items is listed with checkboxes for further actions. While I am able to select an item from t ...

The condition is not functioning properly when the array's length is greater than 1

Within the primary controller, there is an if-else statement: var entity = shareDataService.getModalEntity(); if (entity = "NULL" || entity.length === 1) { myDataPromise = getDataService.getDataFromREST(security); console.log("HERE") } else { ...

Unsure about module loading with system.js and navigating Typescript

I am currently in the process of transitioning an ASP.Net MVC application to Angular2, and I've encountered some perplexing behavior that I can't seem to grasp. Within my Angular2 app, I have a separate Layoutview that allows me to switch betwee ...

Fade In Effect in Angular 2 Using SwitchCase

Hi everyone, I'm facing an issue with making my switch cases fade in after one is called. Here's what I have so far. When the correct switch case is entered in the input field, I want the current one to fade out and the new one to fade in. How ...

The angularjs namespace plays a crucial role within the $stateProvider.state function

I have the following states set up in my application: .state('app.users', { url: '/Users', title: 'Users', templateUrl: helper.basepath('User/Index') }) ...

Adding additional functionalities to ng-blur within the controller: A step-by-step guide

I am seeking to enhance the functionality of ng-blur for all input and textarea fields by adding a new function. These elements already have an existing ng-blur defined in the HTML, and my goal is to incorporate a new function into this existing setup from ...

How many controllers should be assigned to each view and what is the best way to allocate them?

Seeking feedback on controllers and views. Currently, I assign 1 controller per view, giving the controller responsibility for the entire view. However, I have learned that you can use ng-controller to assign multiple controllers to different parts of a ...

"Adjusting the size of a circle to zero in a D3 SVG using Angular 2

Trying to create a basic line graph using d3 in Angular 2 typescript. Below is the code snippet: import { Component, ViewChild, ElementRef, Input, OnInit } from '@angular/core'; import * as d3 from 'd3'; @Component({ selector: 'm ...

Assign object properties to a constant variable while validating the values

When receiving the features object, I am assigning its values to constants based on their properties. const { featureCode, featureSubType, contentId, price, family: { relationCountsConfig: { motherCount, fatherCount, childrenCount }, max ...

Resolve the problem in Angular 6 related to an unused type and the absence of a certain property

I recently watched a video tutorial (link: https://www.youtube.com/watch?v=z4JUm0Bq9AM) and encountered some errors in my CLI. The specific errors are as follows: ERROR in sidebar.component.ts(12,5): error TS7028: Unused label. sidebar.component.ts(14,56 ...

Angular2 tutorial with VS2015 may encounter a call-signature error that is expected

Currently following the Angular2 tutorial in VS2015 and encountering an issue with a warning that is impeding the compilation of one of my TypeScript files. The link to the tutorial is provided below. https://angular.io/docs/ts/latest/tutorial/toh-pt4.htm ...

What is the appropriate event type to pass to the onKeyPressed function in a React application utilizing MaterialUI and written with Typescript?

I am currently working on a React application using Typescript and MaterialUI, where I have implemented a TextField component. My goal is to capture the value of the input HTML element when the user presses the enter key. To achieve this, I have created ...

Despite providing a type, Typescript continues to display an error claiming that the property 'children' does not exist on the type 'FC<ProvidersProps>'

I have set up the props interface, but I am still encountering an error. Property 'children' does not exist on type 'FC'. 'use clilent' import React, { FC, ReactNode } from 'react' import { Toaster } from 'rea ...

Arranging information within the Ngb-Accordion

Welcome to the code snippet showcasing how to create an accordion in Angular: <ngb-accordion [closeOthers]="false" activeIds="0"> <ng-container class="card" *ngFor="let post of Posts"> <ngb-panel title="{{post.title}} - ...

Steps for resolving the problem of the Express error handler not being executed

This question has come up again, and I have searched for solutions but none seem to work. Your assistance in debugging the issue would be greatly appreciated. I have a separate errorHandler set up as middleware. In my error-handler.ts file: import expres ...

Best practices for effectively managing interface design

My current interface looks like this: export interface Folder { name: string; id: number; date: Date; } However, in the actual scenario, the JSON response provides the date as a string type. How should I handle this data transfer between the back-en ...

Handling linting errors for getInitialProps return type in NextJS with Typescript

I've been grappling with this problem for an extended period, and despite numerous attempts, I haven't been able to resolve it. My issue revolves around a basic page named one.tsx. Its structure is as follows: The linting error that's plag ...

Generate a fresh array from the existing array and extract various properties to form a child object or sub-array

I am dealing with an array of Responses that contain multiple IDs along with different question answers. Responses = [0:{Id : 1,Name : John, QuestionId :1,Answer :8}, 1:{Id : 1,Name : John, QuestionId :2,Answer :9}, 2:{Id : 1,Name : John, QuestionId :3,An ...

The data is not being displayed in the table

I am encountering an issue while attempting to populate the table with data received through props by looping over it. Unfortunately, the data is not rendering on the UI :( However, when I manually input data, it does show up. Below is my code: Code for P ...