Angular 9:一种形式的多个 ngb-typeahead?

Posted

技术标签:

【中文标题】Angular 9:一种形式的多个 ngb-typeahead?【英文标题】:Angular 9: More than one ngb-typeahead in one form? 【发布时间】:2020-08-03 10:51:31 【问题描述】:

我在我的 Angular 9 应用程序中使用 NgbTypeahead component from NG-Boostrap 6.0.3。第一个工作正常,但我的表单有很多。

我是否需要为它们中的每一个添加一个单独的 ViewChild 和一个单独的搜索功能?还是我错过了什么?有人可以给我举个例子吗?

作为参考,这里有一个Stackblitz,只有一个。

【问题讨论】:

是的,你需要两个“搜索”和两个 ViewChilds 谢谢。我害怕那个。 好吧,对不起我的快速评论,当然你可以使用独特的搜索功能(不可能是什么)看到我的回答并道歉我的评论 【参考方案1】:

好吧,我的评论真的不正确,假设你有 2 个 ngbTypeHead 你需要那个 focus$ 并且 click$ 是一个数组,为此,你可以使用 map,有些像

focus$ = [0,1].map(_=>new Subject<string>());
click$ = [0,1].map(_=>new Subject<string>());

好吧,你也可以做一些类似的(我使用傻瓜数组和地图)但它是一样的:

focus$ = [new Subject<string>(),new Subject<string>()];

我对模型使用了一个数组

model: any[]=[];

并更改作为参数接收的searchFunction:一个索引,一个实例和一个术语(索引是必要的参考主题

searchType(index,instance, text$) 
    return (text$: Observable<string>) => 
      const debouncedText$ = text$.pipe(
        debounceTime(200),
        distinctUntilChanged()
      );
      const clicksWithClosedPopup$ = this.click$[index].pipe(
        filter(() => !instance.isPopupOpen())
      );
      const inputFocus$ = this.focus$[index];

      return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(
        map(term =>
          (term === ""
            ? states
            : states.filter(
                v => v.toLowerCase().indexOf(term.toLowerCase()) > -1
              )
          ).slice(0, 10)
        )
      );
    ;
  

那么,我们唯一需要的就是改变我们的 ngbTypeahead

  <input
        ...
  [(ngModel)]="model[index]"
  [ngbTypeahead]="searchType(i,instance,$text)"
  (focus)="focus$[i].next($any($event).target.value)"
  (click)="click$[i].next($any($event).target.value)"
  #instance="ngbTypeahead"
  >

你可以在stackblitz看到一个例子

更新如果我们需要不同的数据,我们可以改进传递“数据”的函数搜索,所以,如果我们添加一个新的参数来搜索:

searchType(index,instance, data,text$)  //<--pass "data"
    return (text$: Observable<string>) => 
      const debouncedText$ = text$.pipe(
        debounceTime(200),
        distinctUntilChanged()
      );
      const clicksWithClosedPopup$ = this.click$[index].pipe(
        filter(() => !instance.isPopupOpen())
      );
      const inputFocus$ = this.focus$[index];

      return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(
        map(term =>
          (term === ""
            ? data          //<--here use data
            : data.filter(  //<--here use data too
                v => v.toLowerCase().indexOf(term.toLowerCase()) > -1
              )
          ).slice(0, 10)
        )
      );
    ;
  

我们可以换个叫法写:

[ngbTypeahead]="searchType(i,instance,states,$text)"

另一种选择是,根据“索引”在一个或另一个数组中搜索,所以函数变得像

searchType(index,instance, text$)  
    const data=index==0?states:this.fruits; //<--the data according the index
    return (text$: Observable<string>) => 
      const debouncedText$ = text$.pipe(
        debounceTime(200),
        distinctUntilChanged()
      );
      const clicksWithClosedPopup$ = this.click$[index].pipe(
        filter(() => !instance.isPopupOpen())
      );
      const inputFocus$ = this.focus$[index];

      return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(
        map(term =>
          (term === ""
            ? data          //<--here use data
            : data.filter(  //<--here use data too
                v => v.toLowerCase().indexOf(term.toLowerCase()) > -1
              )
          ).slice(0, 10)
        )
      );
    ;
  

【讨论】:

聪明的解决方案,谢谢。让我难过的部分是菜单的数据源(此处为“状态”)位于搜索功能内。显然,我的每个菜单都有不同的菜单项数组源。我认为最好从 html 实例中传递它:这个菜单是状态,这个菜单是国家等。 您可以将数据作为参数传递给函数搜索。我更新了我的答案和stackblitz,真的这是一个“丑陋的黑客”如何在stackblitz中传递数据,我使用三元运算符,因为只有2个ngbTypeHead。另一个功能是,根据“索引”,是否在数组中搜索

以上是关于Angular 9:一种形式的多个 ngb-typeahead?的主要内容,如果未能解决你的问题,请参考以下文章

Angular / RxJs对一个observable的多个订阅

Angular2 动态生成响应式表单

如何在反应式表单中设置模型数据,Angular 9

Angular 强类型反应形式

推荐 15 个 Angular.js 应用扩展指令

angularJS1笔记-(19)-angular异步加载包的方式