最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular ng-select "No Items Found" error when typing in characters to filter - Stack Overflow

programmeradmin0浏览0评论

I have a ng-select ponent whose drop-down items look like this image above.

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 ponent's own code, there is this filter 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.

// Code within the ponent
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.

<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?

I have a ng-select ponent whose drop-down items look like this image above.

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 ponent's own code, there is this filter 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.

// Code within the ponent
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.

<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?

Share Improve this question edited May 27, 2020 at 9:09 JWP asked May 26, 2020 at 17:13 JWPJWP 6,9753 gold badges57 silver badges77 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 3

Ok found out more about ng-select internals and a solution for proper dropdown filtering as one types.

The key to understanding this is this statement in the ponent's own filter function shown here.

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

This statement allows the user to inject a function, if it's not there; then the default searchFn is used.

To inject your own SearchFn, put this into the ng-select html. You will want this for specific plex 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. That function looks like this:

    _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. I believe this is a bug because I used the tmp-lbl template. 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.

<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.

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.

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

But you cannot access the itemsList.FilteredItems from here as it's read-only. 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.

发布评论

评论列表(0)

  1. 暂无评论