Поиск по группам

Группировка опций в Tom Select строится вокруг механизма optgroups, который позволяет объединять элементы списка в логические секции. При работе с поиском внутри таких списков возникает дополнительный уровень поведения: совпадения могут учитываться как по самим элементам, так и по данным группы, к которой они относятся. Это особенно важно при построении справочников, каталогов и многоуровневых селекторов.


Структура данных с группами

Основой работы является передача данных в формате объектов с указанием группы:

new TomSelect('#select', {
  options: [
    { id: 1, title: 'iPhone 15', category: 'Apple' },
    { id: 2, title: 'MacBook Pro', category: 'Apple' },
    { id: 3, title: 'Galaxy S24', category: 'Samsung' },
    { id: 4, title: 'Galaxy Tab', category: 'Samsung' }
  ],

  optgroups: [
    { value: 'Apple', label: 'Apple' },
    { value: 'Samsung', label: 'Samsung' }
  ],

  optgroupField: 'category',

  labelField: 'title',
  valueField: 'id',
  searchField: ['title']
});

Ключевые параметры

  • optgroupField — поле, определяющее принадлежность элемента к группе
  • optgroups — список групп с метками
  • labelField — отображаемое название элемента
  • searchField — поля, участвующие в поиске

Базовый поиск внутри групп

По умолчанию механизм поиска работает только с полями, указанными в searchField. Это означает, что:

  • группы не участвуют в поиске автоматически
  • совпадение происходит только по элементам
  • визуальная группировка сохраняется при фильтрации

Пример поведения:

searchField: ['title']

Поиск по строке Galaxy вернёт элементы из группы Samsung, но сама группа не является фактором поиска.


Включение группы в поиск

Для того чтобы поиск учитывал название группы, необходимо расширить searchField:

searchField: ['title', 'category']

В этом случае:

  • ввод Apple будет находить все элементы группы Apple
  • поиск по названию группы работает наравне с поиском по элементам
  • результат агрегируется без изменения структуры optgroup

Расширенный контроль релевантности

Tom Select использует механизм score-функции, который позволяет управлять ранжированием результатов поиска.

Базовая настройка score

new TomSelect('#select', {
  searchField: ['title', 'category'],

  score: function(search) {
    return function(item) {
      let score = 0;

      if (item.title && item.title.toLowerCase().includes(search.toLowerCase())) {
        score += 10;
      }

      if (item.category && item.category.toLowerCase().includes(search.toLowerCase())) {
        score += 5;
      }

      return score;
    };
  }
});

Принцип работы

  • функция score возвращает функцию оценки элемента
  • каждый элемент получает числовой рейтинг
  • чем выше значение, тем выше позиция в выдаче
  • группы при этом наследуют поведение элементов

Сохранение структуры групп при фильтрации

При поиске возможна ситуация, когда группа остаётся пустой. Поведение зависит от конфигурации:

  • пустые группы могут скрываться
  • или оставаться в списке без элементов

Для управления этим используется кастомная логика рендеринга:

render: {
  optgroup_header: function(data, escape) {
    return `<div class="optgroup-header">${escape(data.label)}</div>`;
  }
}

Поиск с приоритетом групп

В сложных интерфейсах требуется, чтобы совпадение по группе имело более высокий приоритет, чем совпадение по элементам.

score: function(search) {
  const s = search.toLowerCase();

  return function(item) {
    const titleMatch = item.title?.toLowerCase().includes(s);
    const groupMatch = item.category?.toLowerCase().includes(s);

    if (groupMatch && titleMatch) return 100;
    if (groupMatch) return 50;
    if (titleMatch) return 10;

    return 0;
  };
}

Такой подход позволяет:

  • поднимать вверх целые группы
  • усиливать значимость совпадений по категории
  • формировать иерархический поиск без изменения структуры данных

Фильтрация внутри optgroups

Дополнительный уровень контроля достигается через предобработку данных перед передачей в Tom Select.

function filterOptions(query, options) {
  return options.filter(item => {
    return item.title.toLowerCase().includes(query.toLowerCase())
      || item.category.toLowerCase().includes(query.toLowerCase());
  });
}

Данный подход применяется при:

  • серверной фильтрации
  • больших наборах данных
  • динамической подгрузке

Рендеринг результатов с учётом поиска

Отображение групп и элементов можно адаптировать под контекст поиска:

render: {
  option: function(data, escape) {
    return `
      <div class="option">
        <span class="title">${escape(data.title)}</span>
        <span class="meta">${escape(data.category)}</span>
      </div>
    `;
  }
}

В сочетании с поиском по группам это позволяет визуально разделять:

  • совпадение по названию товара
  • совпадение по категории
  • смешанные результаты

Управление поведением групп при поиске

Внутренний механизм Tom Select не отделяет группы от элементов логически — группы являются контейнером. Однако поведение можно контролировать следующими приёмами:

Сортировка внутри групп

sortField: [
  { field: 'title', direction: 'asc' }
]

Стабилизация порядка групп

lockOptgroupOrder: true

Это позволяет сохранить исходную структуру даже при активной фильтрации.


Поиск с учётом нескольких полей и групповой логики

При сложных данных используется комбинированный подход:

new TomSelect('#select', {
  searchField: ['title', 'category', 'tags'],

  optgroupField: 'category',

  score: function(search) {
    return function(item) {
      let score = 0;

      const s = search.toLowerCase();

      if (item.title?.toLowerCase().includes(s)) score += 20;
      if (item.category?.toLowerCase().includes(s)) score += 10;
      if (item.tags?.some(t => t.toLowerCase().includes(s))) score += 5;

      return score;
    };
  }
});

Такая конфигурация создаёт многоуровневую систему поиска:

  • основной приоритет — совпадение по названию
  • вторичный уровень — совпадение по группе
  • третичный — по тегам

Поведение пустых групп при фильтрации

При поиске может возникать ситуация, когда:

  • элементы группы не соответствуют запросу
  • но сама группа остаётся в DOM

Для скрытия пустых групп применяется кастомное управление через обработку данных перед рендером:

onChange: function() {
  this.refreshOptions(false);
}

Или через фильтрацию исходного массива данных.


Итоговая модель поиска по группам

Логика поиска в группированных списках Tom Select строится на трёх уровнях:

  • уровень данных — поля searchField
  • уровень группировкиoptgroupField
  • уровень релевантностиscore

Комбинация этих механизмов формирует гибкую систему, в которой группы могут:

  • участвовать в поиске
  • влиять на сортировку
  • изменять структуру выдачи без изменения исходных данных