Add selected items to ng-select with multiple and typeahead

Viewed 5261

I'm using ng-select to select multiple values from a large list that is remotely loaded depending on what the user types in the box. Here are my requirements:

  1. Tags added dynamically
  2. Dropdown is not displayed for already selected values. It is only for typeahead of available, unselected values.

Here are the problems that I've run into so far:

  • Selected tags do not get displayed if not part of the items list.
  • Using the tag objects as an array with [(ngModel)] makes ng-select treat it like the value doesn't exist at all. ng-select seems to only use IDs for [(ngModel)] when [mutiple]=true, as opposed to the selected object when [multiple]=false
  • The tagsInput$ observable doesn't get fired if [isOpen]=false

I have verified that tagsService is operating correctly.

Current View:

<ng-select [items]="tags$ | async"
           bindValue="name"
           [loading]="tagsLoading"
           [typeahead]="tagsInput$"
           [multiple]="true"
           [isOpen]="tagsOpen"
           [searchFn]="filterSelectedTags"
           [(ngModel)]="selectedTagIds"></ng-select>

Current Controller:

class TagFormComponent {

  public tags$: Observable<Tag[]>;
  public tagsLoading: boolean;
  public tagsInput$: Subject<string>;
  public tagsChanger$: Subject<Tag[]>;
  public selectedTags: Tag[];
  public selectedTagIds: number[];
  public tagsOpen: boolean;

  constructor(private tagService: TagService) {

    this.tagsInput$ = new Subject<string>();
    this.tagsChanger$ = new Subject<Tag[]>();
    this.tagsChanger$.subscribe( tags => {
      this.selectedTagIds = tags.map(t => t.id);
      this.selectedTags = tags;
    });
    this.tags$ = concat(
      this.tagsChanger$,
      this.tagsInput$.pipe(
        debounceTime(200),
        distinctUntilChanged(),
        tap( () => {
          this.tagsOpen = true;
          this.tagsLoading = true;
        }),
        switchMap(q => this.tagService.search(q).pipe(
          catchError( err => { this.tagsLoading = false; console.error(err); return of([] ); }),
          tap( () => this.tagsLoading = false)
        ))
      )
    );

    this.tagsChanger$.next(this.assetGroup.tags);
  }

  public matcher(a: any, b: any): boolean {
    return !!a && b && a.id === b.id;
  }

  public filterSelectedTags(_q: string, item: Tag) {
    return !this.selectedTagIds.includes(item.id);
  }

  public tagAdded() {
    this.tagsOpen = false;
  }
}
0 Answers
Related