Angular ошибка ng-select «Элементы не найдены» при вводе символов для фильтрации - PullRequest
0 голосов
/ 26 мая 2020

dropsown

У меня есть компонент ng-select, раскрывающиеся элементы которого выглядят как на изображении выше.

При попытке отфильтровать список, Я ввожу символы в элемент управления вводом и вижу следующее: «Элементы не найдены», несмотря на то, что они есть в списке.

enter image description here

Вот что я Я попытался разобраться в этом ...

В собственном коде компонента есть эта функция фильтра. На основе установки точек останова я обнаружил, что 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);
            }
        }
    }

Таким образом, элементы не найдены, потому что список элементов. filterItems всегда имеет значение 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>

Вот HTML, не забыл ли я что-то, чтобы фильтрация работала при вводе символов?

1 Ответ

0 голосов
/ 27 мая 2020

Ok узнал больше о внутреннем устройстве ng-select и решении для правильной выпадающей фильтрации как одного типа.

Ключом к пониманию этого является этот оператор в собственной функции фильтрации компонента, показанной здесь.

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

Этот оператор позволяет пользователю внедрить функцию, если ее нет; тогда используется searchFn по умолчанию.

Чтобы ввести свой собственный SearchFn, поместите его в ng-select html. Вам понадобится это для определенного c сложного поиска.

   <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); 

Если у вас нет зарегистрированного метода SearchFn, вызывается defaultSearchFn. Эта функция выглядит так:

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

Эта функция не смогла ничего найти в моей ситуации, потому что не было opt.label. Я считаю, что это ошибка, потому что я использовал шаблон tmp-lbl. В режиме отладки все элементы при входе были правильными, но индекс так и не был найден.

Здесь был шаблон ng-label-tmp, который должен был установить значение opt.label.

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

[bindLabel] не работал, потому что он привязывается только к отдельным полям.

Если у вас нет зарегистрированного Searchfn и ничего не найдено через _defaultSearchFn, тогда последний шанс упущен для пользователя, если вы зарегистрировали обработчик onSearch, подобный этому.

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

Но вы не можете получить доступ к itemsList.FilteredItems отсюда, поскольку он доступен только для чтения. Событие отправляет термин и элементы, над которыми нужно работать.

Доступ к нему также осуществляется из следующего кода:

 @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)
         );
      }); 

Обратите внимание, что этот метод требует, чтобы вы поддерживали и связывали собственный фильтр список. Фу ...

Лучшее решение - использовать вашу собственную функцию встроенного поиска.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...