如何使 ng-bootstrap typeahead 显示带有 link 的下拉结果

How to make ng-bootstrap typeahead show dropdown results with a link

我无法让我的歌曲服务的结果显示在我的 ng-bootstrap 预输入结果中。我收到错误:"Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays."

我尝试按照 ng-bootstrap 站点上的维基百科示例进行操作:https://ng-bootstrap.github.io/#/components/typeahead/examples#http

我的 .ts 文件有:

formatter = (x: { title: string }) => x.title;

  searchSongTitles = (text$: Observable<string>) =>
text$.pipe(
  debounceTime(800),
  distinctUntilChanged(),
  tap(() => this.loadingNavbarSearchSongs$ = true),
  switchMap(term =>
    this.songsService.getSongsQuickSearch(term, this.titleMatchType$, this.sort$, this.sortDirection$).pipe(
      tap(() => this.loadingNavbarSearchSongsFailed$ = false),
      catchError(() => {
        this.loadingNavbarSearchSongsFailed$ = true;
        return of([]);
      })
    )
  ),
  tap(() => this.loadingNavbarSearchSongs$ = false)
)

我的 .html 文件有:

<input id="songtitles-search" placeholder="Song Title" type="text" 
class="form-control form-control-sm my-sm-0 mr-sm-2" 
name="song_titles_search" [(ngModel)]="songTitlesSearchText$" 
[ngbTypeahead]="searchSongTitles" [resultFormatter]="formatter" 
[inputFormatter]="formatter">

型号: songsService.getSongsQuickSearch returns 一个 Observable<Song[]> 其中 Song 具有以下属性: 身份证号; 标题:字符串;

我需要获取来自 getSongsQuickSearch 方法的歌曲数组,以便它们在 link 下拉菜单中可点击歌曲标题 links 到基于其 id 的歌曲详细信息页面。例如:

<a [routerLink]="['/song-details', song.id]">{{ song.title }}</a>

我最终使用了带有自定义响应视图的 ng-bootstrap typeahead。这是使用 Angular "^7.0.1" 和 "bootstrap": "^4.1.3" 和 @ng-bootstrap/ng-bootstrap": "^3.3.1"

这是我用来使搜索结果显示在搜索输入下方的自定义 CSS:

#search-results {
    position: absolute;
    width: 160px; /*How wide the results are*/
    background: white;
    border-bottom-left-radius: 10px;
    border-bottom-right-radius: 10px;
    max-height: 500px; /* How far down the results will show */
    overflow-y: auto; /* Show scrollbar if results overflow vertically */
    overflow-x: none; /* Do not show scrollbar horizontally if results overflow */
    border: 1px solid gray;
    left: 150px; /*Where from the left side of the screen the results container starts*/
    right: 0;
    top: 44px; /*Make the results container show under search input*/
}

这是搜索视图:

<form class="form-inline">
    <input id="songtitles-search" placeholder="Song Title" type="text" class="navbar- 
    search form-control form-control-sm my-sm-0 mr-sm-2" name="song_titles_search" 
    [(ngModel)]="songTitlesSearchText$" [ngbTypeahead]="searchSongTitles">
    <ul id="search-results" class="list-group">
        <li *ngIf="loadingNavbarSearchSongs$" class="list-group-item">
            <img class="small-image" style="width:8em; height:8em;" 
            src="assets/img/loading.gif" />
        </li>
        <li *ngFor="let song of songs$" class="list-group-item">
            <a (click)="songSearchResultChosen()" [routerLink]="['/song-details', 
            song.id]">{{ song.title }}</a> - {{song.main_main_artist}}
        </li>
        <li *ngIf="showNoSearchResultsMessage$">
            <strong>No Song(s) Found Matching Search Criteria</strong>
        </li>
    </ul>
    <button class="btn btn-primary btn-sm my-2 my-sm-0 mr-sm-2" type="submit">
        Search
    </button>
</form>

这是 typescript typeahead 代码:

searchSongTitles = (text$: Observable<string>) =>
text$.pipe(
  debounceTime(800),
  distinctUntilChanged(),
  map(term => {
    this.songs$ = [];
    this.showNoSearchResultsMessage$ = false;
    if (term.length > 0) {
      this.songTitlesSearchText$ = term;
      this.getSongs();
    } else {
      this.loadingNavbarSearchSongs$ = false;
    }
  }
  )
)

这是调用我设置的服务的 getSongs 方法

getSongs() {
  this.loadingNavbarSearchSongs$ = true;

  this.songsService.getSongsQuickSearch(this.songTitlesSearchText$, this.titleMatchType$,
    this.sort$, this.sortDirection$).subscribe(
    response => {
      this.songs$ = response.songs;
      this.loadingNavbarSearchSongs$ = false;
      if (this.songs$.length <= 0) {
        this.showNoSearchResultsMessage$ = true;
      }
    }
  );
}

您可以在我网站的导航栏中看到一个工作示例 abovetempo.com 希望这对正在寻找此解决方案的其他人有所帮助!

另一种方法是使用 ng-template。我会将其添加为评论,但我没有足够的声誉。希望它可以帮助其他人寻找相同的解决方案。

https://ng-bootstrap.github.io/#/components/typeahead/examples#template