Reputation: 1002
I have several ng-select (Custom server-side search) dropdowns created by a *ngFor directive, having the possibility to pick multiple items from each dropdown.
The problem however is that each time I search for something and pick a value, that value will be selected for all the other ng-select dropdowns as well. Also I need to make the option values returned by the api based on the iteration's variable
Stackblitz: https://stackblitz.com/edit/angular-vml2j8
filter.component.html:
<div *ngFor="let filter of filters;index as i">
<ng-select [items]="filterValues | async"
[typeahead]="filterValuesInput"
[multiple]="true"
(open)="ngSelectOpened(filter.name)"
[loading]="filterValuesLoading"
bindLabel="name"
[(ngModel)]="selectedFilterValues[pref.name]">
</ng-select>
</div>
filter.component.ts
filterValues: Observable<FilterValues[]>;
filterValuesLoading = false;
filterValuesInput = new Subject<string>();
selectedFilterValues];
ngSelectOpened(filterName) {
this.filterValues = concat(
of([]), // default items
this.filterValuesInput.pipe(
distinctUntilChanged(),
tap(() => this.filterValuesLoading = true),
switchMap(term => this.dataService.getData(term).pipe(
catchError(() => of([])), // empty list on error
tap(() => this.filterValuesLoading = false)
))
)
);
}
How can I make the ng-select work based on current iteration?
Upvotes: 2
Views: 8867
Reputation: 1
<ng-container *ngFor="let item of data; let i=index">
<ng-select id={{i}} name={{i}} class="custom" placeholder="Select"
[items]="dataDropdown" bindLabel="Code" bindValue="Key"
[(ngModel)]="item.Key" [virtualScroll]="true" trim="blur" (open)="ngSelectOpened(item.Nm)"
*ngIf="pageMode.toLocaleLowerCase() === 'add' || pageMode.toLocaleLowerCase() === 'edit'" autocomplete="off">
</ng-select>
</ng-container>
ngSelectOpened(name: string) {
this.dataDropdown = JSON.parse(JSON.stringify(this.dynamicdropdown.filter(x => x.ratingAgencyNm === agencyname)))
}
deep copied the dropdown values to another variable and filter it on ngfor loop through and updated the original dropdown variable on open event
Upvotes: 0
Reputation: 2332
Maybe not most elegant but seems to work. Previously your selectedPersons
were shared between all lists.
Changed Html:
<div *ngFor="let pref of filters">
<ng-select [items]="people$ | async"
bindLabel="name"
[addTag]="true"
[multiple]="true"
[hideSelected]="true"
[trackByFn]="trackByFn"
[minTermLength]="2"
(open)="ngSelectOpened(pref.name)"
[loading]="peopleLoading"
typeToSearchText="Please enter 2 or more characters"
[typeahead]="peopleInput$"
[(ngModel)]="pref.selected">
</ng-select>
<br>
</div>
Changed ts (2 lists):
import { Component } from '@angular/core';
import { DataService, Person } from '../data.service';
import { concat, Observable, of, Subject } from 'rxjs';
import { catchError, debounceTime, distinctUntilChanged, switchMap, tap } from 'rxjs/operators';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
people$: Observable<Person[]>;
peopleLoading = false;
peopleInput$ = new Subject<string>();
selectedPersons: Person[] = <any>[{ name: 'Karyn Wright' }, { name: 'Other' }];
filters = [
{id: 1, name: "Filter1", selected: [...this.selectedPersons]},
{id: 2, name: "Filter2", selected: [...this.selectedPersons]}/*,
{id: 3, name: "Filter3"}*/
]
constructor(private dataService: DataService) {
}
ngSelectOpened(filterName) {
this.loadPeople(filterName);
}
private loadPeople(filterName) {
this.people$ = concat(
of([]), // default items
this.peopleInput$.pipe(
distinctUntilChanged(),
tap(() => this.peopleLoading = true),
switchMap(term => this.dataService.getPeople(term).pipe(
catchError(() => of([])), // empty list on error
tap(() => this.peopleLoading = false)
))
)
);
}
}
Upvotes: 1