Managing two select fields in a dynamic Angular form - best practices

On my screen, I am dynamically creating elements using a reactive form. Specifically, I am creating cards with two selection fields each:

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

Situation: When I add a card and choose a layout, the options for that specific layout are fetched and displayed in the asset select through an API filter service. However, when I add another card and select a different layout option, both asset selects end up with the same option.

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

Template

<div class="card"
  formArrayName="scriptOperationOrders" 
  *ngFor="let workstation of formOperation.get('scriptOperationOrders')['controls']; index as idx"
>
  <div class="card-body" [formGroupName]="idx">
    <div class="form-row">
      <div class="form-group col-md-1">
        <label>Rank</label>
        <input type="text" name="rank" class="form-control" formControlName="rank"/>
      </div>
      <div class="form-group col-md-2">
        <label>Layout</label>
        <select formGroupName="layout" (ngModelChange)="searchAssetsByLayouts($event)">
          <option value="">Choose Layout</option>
          <option 
            *ngFor="let lay of (layouts$ | async)?.dataArray " 
            [value]="lay.id">{{ lay.description }}
          </option>
        </select>
      </div>
      <div class="form-group col-md-2">
        <label>Asset</label>
        <select formGroupName="asset">
          <option value="">Choose Asset</option>
          <option 
            *ngFor="let asset of (assets$ | async)?.dataArray " 
            [value]="asset.id">{{ asset.description }}
          </option>
        </select>
      </div>
    </div>
  </div>
</div>

Controller

layouts$: Observable<IResponse<ILayoutModel>>;
assets$: Observable<IResponse<IAssetModel>>;

ngOnInit() {
  ...
  this.buildFormOperation();
  this.layouts$ = this.layoutService.listLayouts();
  this.providers$ = this.providerService.listProviders();
}

buildFormOperation() {
  this.formOperation = this.fb.group({
    script: [],
    descriptionCode: [],
    description: [],
    scriptOperationOrders: new FormArray([])
  })
}

searchAssetsByLayouts(layoutId: number) {
  this.assets$ = this.assetService.listAssetsRoots(layoutId); // The assets$ variable is overridden here
}

Asset listing Service

listAssetsRoots(layoutId?: number | string): Observable<IResponse<IAssetModel>> {
  return this.apiService.crudeList({
    url: `${this.url}/roots`,
    queryParams: {
      layoutId
    },
  })
  .pipe(map((res) => {
    return new IResponse<IAssetModel>(res, IAssetModel);
  }));
}

When selecting a layout option, only the corresponding layout's options should be shown in the asset select on the same card.

Answer №1

this.assets$ = this.assetService.listAssetsRoots(layoutId);
as The assets$ variable is being reassigned at this point
ts file:-

// Specifying the expected response type 
interface Assets{
  id:number,
  description :string
}
// Initializing with an empty array
assets$ : Observable<Assets[]> = of([]);


// Adding a second argument idx as row_index
 
 searchAssetsByLayouts(layoutId: number,row_index:number) {
  this.assets$[row_index] = this.assetService.listAssetsRoots(layoutId); // The assets$ variable is now updated without overriding
}

//html:-
//Using formControlName for 'layout' and 'asset' control instead of formGroupName
//and passing 'idx' as a second parameter to (ngModelChange)="searchAssetsByLayouts($event,idx)

<div class="card"
  formArrayName="scriptOperationOrders" 
  *ngFor="let workstation of formOperation.get('scriptOperationOrders')['controls']; index as idx"
>
  <div class="card-body" [formGroupName]="idx">
    <div class="form-row">
      <div class="form-group col-md-1">
        <label>Rank</label>
        <input type="text" name="rank" class="form-control" formControlName="rank"/>
      </div>
      <div class="form-group col-md-2">
        <label>Layout</label>
        <select formControlName="layout" (ngModelChange)="searchAssetsByLayouts($event,idx)">
          <option value="">Choose Layout</option>
          <option 
            *ngFor="let lay of (layouts$ | async)?.dataArray " 
            [value]="lay.id">{{ lay.description }}
          </option>
        </select>
      </div>
      <div class="form-group col-md-2">
        <label>Asset</label>
           <select formControlName="asset">
                  <option value="">Choose Asset</option>
                  <option 
                    *ngFor="let asset of (assets$[idx] | async)" 
                    [value]="asset.id">{{ asset.description }}
                  </option>
         </select>
      </div>
    </div>
  </div>
</div>

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

Enhancing Textures in Three.js: Methods for Gradually Improving Resolution

I am currently working on a Three.js chart that displays multiple images on a 2D plane. At the moment, each individual image is a 32px by 32px segment of larger 2048px by 2048px image atlas files. I intend to enlarge these individual images when users zoo ...

The parameters provided for ionic2 do not align with any acceptable signature for the call target

Currently, I have 3 pages named adopt, adopt-design, and adopt-invite. To navigate between these pages, I am using navCtrl.push() to move forward and to go back to the previous page. Everything works smoothly on the browser, but when I try to build it for ...

Tips for retrieving Angular routing data from external sources outside of an Angular application

Is there a way to automatically generate a sitemap for each module during build time? The project structure is as follows: - cli - client -- Module A -- Routing A -- Module B -- Routing B -- Module C -- Routing C - server I am ...

Display "No results found" on the auto-complete search list when the specified element does not exist

If the element does not exist in the "ul list," I want my search code (autocomplete on an input field) to display a message like "no match found" as a div tag or some other form of notification. How can I achieve this? Do I need to implement a different ...

Issue with the functionality of Angular reactive custom validator inoperable

Recently, I created a simple validator that compares the values of two date form controls within a form group. The basic rule is that the maturityDate has to be greater than the valueDate, otherwise the form group should be marked as invalid. Here is how ...

Confirmation dialog with user-defined button text

When the confirm prompt box is used, it typically displays "ok" and "cancel" buttons. I am looking to customize the label text for the buttons to read as Agree and Not Agree instead. If you have any suggestions on how to achieve this modification, please ...

Node.js Sequelize QueryExplore the power of Sequelize in Node.js

I'm looking to filter the "incomers" based on age, but all I have in the table is their date of birth. I want to find people within a specific age range, how can I accomplish this? router.post('/', function (req, res, next) { let parame ...

Converting JavaScript strings into nested arrays

Currently, I am developing my own bi-directional DOM binder to connect input fields to JSON data as a way to enhance my understanding and skills. I have chosen not to use frameworks like Ember, Angular, or KnockoutJS for this project. One challenge I am fa ...

Display <tr> tag when button is clicked without refreshing the page

I have a specific requirement to hide a certain tag initially. If the user clicks the forward button without selecting any radio buttons or checkboxes, the tag should be displayed and the page should not refresh. However, there seems to be an issue with ...

How to assign a custom validator parameter to a form group in Angular

I'm in a situation where I have a form group and need to validate the end date so it is not earlier than the start date. The challenge here lies in accessing specific fields when the form group is not yet declared. dateFormGroup: this.fb.group({ ...

What are some effective ways to integrate the WordPress API with ReactJS?

Wordpress recently introduced an API that allows you to make HTTP requests without worrying about routes, as the backend is handled for you. I'm curious, how can I integrate ReactJs with Wordpress API? This has been a frustrating challenge for me be ...

Guide on saving an Express session into a MongoDB database through a controller handling

I'm experiencing a problem with my controller where the session is not being stored properly even after implementing the necessary express session code app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: true, ...

Retrieve an item from an array using a Select component

Is there a way to retrieve the complete object representation of an item from a list in React? Currently, when I select an item and call handleChangeSelectAuto, the original value from useState is returned instead of the entire object. How can I ensure tha ...

items within an unordered list that can be collapsed

Answer: Nikhil was on the right track with his solution, but I had to make some modifications. Specifically, I needed to create and initialize an empty array to display the details properly. Here's the updated code: if (this.name.toLowerCase() == va ...

A fresh javascript HTML element does not adhere to the css guidelines

While attempting to dynamically add rows to a table using Javascript and jQuery, I encountered an issue. Here is my code: <script> $(document).ready(function(){ for (i=0; i<myvar.length; i++){ $("#items").after('<tr class="item- ...

Avoid the need to refresh the HTML content every time there is a change in the Angular $

One of the challenges I'm facing is with a for loop in my JavaScript: for (var i=0;i<2;i++) { $scope.widget = widgets[i]; $scope.header = widgets[i].data.header; $scope.items = widgets[i].data.items; $scope.footer = widgets[i].data ...

Even though the rxjs imports are correctly set up, the 'map' property is not found on the 'Observable<Response>' type

I'm currently developing a MEAN stack application using Angular 2. Despite finding similar inquiries on StackOverflow, I've explored various solutions without success. While many suggest importing the entire rx/js library along with map or using ...

Using RxJS to send a series of distinct AJAX requests on an event

Suppose I have an event type, such as a click event. I need to initiate 3 separate ajax requests through this event, but I want to listen for the final result of all 3 requests. What would be the most suitable design pattern for implementing this sequence ...

Inconsistent outcomes during the evaluation of Angular services

I encountered an issue while attempting to test an Angular service. Here is the code for my service: import { Ipersons } from './ipersons'; import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/ht ...

How can I create the effect of text changing color automatically after a specified time period has elapsed

I am currently dealing with a timer that is functioning properly, but I have a specific CSS inquiry. Essentially, what I would like to achieve is when the timer hits 30 seconds, I want the numbers to change to red color. $(function () { var $startTimer = ...