简体   繁体   English

Angular ng-select “No Items Found” 在输入要过滤的字符时出错

[英]Angular ng-select “No Items Found” error when typing in characters to filter

滴下

I have a ng-select component whose drop-down items look like this image above.我有一个 ng-select 组件,其下拉项看起来像上图。

In an attempt to filter the list, I type in characters into the input control and see this: "No Items Found" despite the fact they are in the list.为了过滤列表,我在输入控件中输入字符并看到:“未找到项目”,尽管它们在列表中。

在此处输入图像描述

Here's what I've done to try to figure this out...这是我为解决这个问题所做的工作......

Within the component's own code, there is this filter function.在组件自己的代码中,有这个过滤器 function。 I have found based on setting breakpoints, that there is no searchFn (according to code flow) so the defaultSearchFn is used but doesn't seem to work.我发现基于设置断点,没有searchFn(根据代码流),所以使用了defaultSearchFn,但似乎不起作用。

// Code within the component
filter(term) {
        if (!term) {
            this.resetFilteredItems();
            return;
        }
        this._filteredItems = [];
        term = this._ngSelect.searchFn ? term : stripSpecialChars(term).toLocaleLowerCase();
        /** @type {?} */
        const match = this._ngSelect.searchFn || this._defaultSearchFn;
        /** @type {?} */
        const hideSelected = this._ngSelect.hideSelected;
//Because there are no groups keys....
        for (const key of Array.from(this._groups.keys())) {
            /** @type {?} */
            const matchedItems = [];
            for (const item of this._groups.get(key)) {
                if (hideSelected && (item.parent && item.parent.selected || item.selected)) {
                    continue;
                }
                /** @type {?} */
                const searchItem = this._ngSelect.searchFn ? item.value : item;
                //match is never called
                if (match(term, searchItem)) {
                    matchedItems.push(item);
                }
            }
//code just skips to this point.
            if (matchedItems.length > 0) {
                const [last] = matchedItems.slice(-1);
                if (last.parent) {
                    /** @type {?} */
                    const head = this._items.find(x => x === last.parent);
                    this._filteredItems.push(head);
                }
                this._filteredItems.push(...matchedItems);
            }
        }
    }

So no items are found because the itemslist.filteredItems is always null.所以找不到项目,因为 itemslist.filteredItems 始终是 null。

<ng-select 
   #select
   (change)="onSelectChanged(select)"
   [(items)]="items"
   [searchable]="true"
   type="text"
>
   <ng-template ng-label-tmp let-item="item">
      <span class="dropdown">
         {{ item.firstName + " " + item.lastName }}
      </span>
   </ng-template>
   <ng-template
      ng-option-tmp
      let-item="item"
      let-search="searchTerm"
      let-index="index"
   >
      <span class="dropdown"
         >{{
            item.firstName +
               " " +
               item.lastName +
               " " +
               item.middleName +
               " " +
               "(" +
               item.id +
               ")"
         }}
      </span>
   </ng-template>
</ng-select>

Here's the HTML, have I forgot something to make the filtering work when characters are typed in?这是 HTML,我是否忘记了在输入字符时使过滤起作用的东西?

Ok found out more about ng-select internals and a solution for proper dropdown filtering as one types.好的,了解更多关于 ng-select 内部结构和正确下拉过滤作为一种类型的解决方案。

The key to understanding this is this statement in the component's own filter function shown here.理解这一点的关键是这里显示的组件自己的过滤器 function 中的这条语句。

    const match = this._ngSelect.searchFn || this._defaultSearchFn;

This statement allows the user to inject a function, if it's not there;此语句允许用户注入 function,如果它不存在; then the default searchFn is used.然后使用默认的 searchFn。

To inject your own SearchFn, put this into the ng-select html.要注入您自己的 SearchFn,请将其放入 ng-select html。 You will want this for specific complex searching.您将需要它用于特定的复杂搜索。

   <ng-select 
    [searchFn]="searchFunction"  //inject your own function here. 
    [items]="filtered" 
     type="text">
 // the itemsList is iterated and this is called for each item
 // just like an array map function
   searchFunction(term, item) {
 // anything returning true makes it into the filtered list
      return item.firstName.includes(term);
   }

  //any matches are pushed into the itemsList.filteredItems list which is read-only to the outside world.
  //see this line up above in the filter method of the ng-select?   
   this._filteredItems.push(...matchedItems); 

If you don't have a registered SearchFn method the defaultSearchFn is called.如果您没有注册的 SearchFn 方法,则会调用 defaultSearchFn。 That function looks like this: function 看起来像这样:

    _defaultSearchFn(search, opt) {
        /** @type {?} */
        const label = stripSpecialChars(opt.label).toLocaleLowerCase();
        return label.indexOf(search) > -1;
    }

That function was failing to find anything in my situation because there was no opt.label. function 在我的情况下找不到任何东西,因为没有 opt.label。 I believe this is a bug because I used the tmp-lbl template.我相信这是一个错误,因为我使用了 tmp-lbl 模板。 In debug mode, the items on entry were all correct but no index was ever found.在调试模式下,条目上的项目都是正确的,但没有找到索引。

Here was the ng-label-tmp template which should have set the opt.label value.这是应该设置 opt.label 值的 ng-label-tmp 模板。

<ng-template ng-label-tmp let-item="item">
      <span>{{ item.firstName + " " + item.lastName }}</span>
   </ng-template>

[bindLabel] didn't work because it only binds to single fields. [bindLabel] 不起作用,因为它只绑定到单个字段。

If you have no Searchfn registered and nothing is found via the _defaultSearchFn, then one last chance is kicked out to the user, if you have registered an onSearch handler like this.如果您没有注册 Searchfn 并且没有通过 _defaultSearchFn 找到任何内容,那么如果您已经注册了这样的 onSearch 处理程序,那么最后一次机会被踢给了用户。

   (search)="onSearchFunction($event, select)"

But you cannot access the itemsList.FilteredItems from here as it's read-only.但是您不能从这里访问 itemsList.FilteredItems,因为它是只读的。 The event sends in the term and items to work on.事件发送术语和要处理的项目。

It is also accessed from code behind like this:它也可以从后面的代码中访问,如下所示:

 @ViewChild(NgSelectComponent, { static: false }) select: NgSelectComponent;
 this.select.searchEvent.subscribe((result) => {
         let term = result.term;
         result.items = this.filtered.find((item) =>
            item.firstName.includes(term)
         );
      }); 

Note that this method requires you to maintain and bind you own filter list.请注意,此方法需要您维护和绑定您自己的过滤器列表。 Yuck...呸...

Best solution is to use your own injected search function.最好的解决方案是使用自己注入的搜索 function。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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