I want to create dependent drop-down list with add more feature. I tried the below code:
Basically this should be the flow:
There are multiple row, all row will have own type, name and description values. the issue is when I complete first row selection with all values of 3 dropdowns and click on add more
then in second row I select type to change the name values but it also changes the first row values. It should not change the value of first row.
I am not getting how to do this according to row added, also all values are populating from API so I can't call api in stackblits.
I must supose your nameList and descList are not an array of string else an array of object (*) So I imagine some like
this.nameList = [
{id:1,typeId:1,name:"Name 1"},
{id:2,typeId:1,name:"Name 2"},
{id:3,typeId:2,name:"Name 1"}
];
this.descList = [
{id:1,nameId:1,desc:"Description 1"},
{id:2,nameId:1,desc:"Description 2"},
{id:3,nameId:2,desc:"Description 3"}
];
So it's easy "filter" the options. But before declare a getter to acces the formArray
get uomArray()
{
return this.productForm.get('uom') as FormArray
}
And change the function to add a new FormGroup
addmore() {
this.uomArray.push(
this.uom()
);
}
See how the .html becomes. the "formArrayName" is in a div alone, the [formGroupName]="i" is in the div you iterate nad you get the "value" of the array as uomArray.value[i].type
I remove the classes to be more clear the code
<form name="productForm" autocomplete="off" [formGroup]="productForm">
<div formArrayName="uom">
<div *ngFor="let item of uomArray.controls; let i = index"
[formGroupName]="i">
{{i+1}}
<select formControlName="type">
<option *ngFor="let list of typeList" [value]="list.tyopeId">
{{ list.typeName }}
</option>
</select>
<select formControlName="name">
<ng-container *ngFor="let list of nameList">
<option *ngIf="list.typeId==uomArray.value[i].type" [value]="list.id">
{{ list.name }}</option>
</ng-container>
</select>
<select formControlName="desc">
<ng-container *ngFor="let list of descList">
<option *ngIf="list.nameId==uomArray.value[i].name" [value]="list.id">
{{ list.desc }}
</option>
</ng-container>
</select>
</div>
</div>
</form>
NOTE: not use the array "controls" of a form array or a formGroup, like your this.productForm.controls["uom"]["controls"] //<--WRONG
to get or iterate the array, the correct way is use this.productForm.get('uom')
Update from your comment, I need supoose you has a service that, according the value of "type" you has a list of nameList and according to the value of "name" you has a list of descList. But the only way is that you has an array of observables, really two (one for types and another one names), and subscribe to changes. The first is transform your function uom()
I supose then that you has a dataService that has two functions
getNames(res){...}
getDescriptions(res){...}
names$:Observables[]=[];
descriptions$:Observables[]=[];
uom() {
const index=this.uomArray().controls?this.uomArray().controls.length:0
const group=this.formBuilder.group({
type: ["", [Validators.required]],
name: ["", [Validators.required]],
desc: ["", [Validators.required]]
});
names$[index]=group.get('type').valueChange.pipe(
map(res=>this.dataService.getNames(res)
)
descriptions$[index]=group.get('name').valueChange.pipe(
map(res=>this.dataService.getDescriptions(res)
)
return group;
}
And you iterate over the observables using pie async
<select formControlName="name">
<option *ngFor="let item of names$[i]|async">{{item}}</option>
</select>
<select formControlName="desc">
<option *ngFor="let item of descriptions$[i]|async">{{item}}</option>
</select>