简体   繁体   中英

Angular ng-select multiple values in *ngFor directive

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?

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)
                ))
            )
        );
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM