Группировка опций в 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 будет находить все элементы группы
AppleTom Select использует механизм 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;
};
}
Такой подход позволяет:
Дополнительный уровень контроля достигается через предобработку данных перед передачей в 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;
};
}
});
Такая конфигурация создаёт многоуровневую систему поиска:
При поиске может возникать ситуация, когда:
Для скрытия пустых групп применяется кастомное управление через обработку данных перед рендером:
onChange: function() {
this.refreshOptions(false);
}
Или через фильтрацию исходного массива данных.
Логика поиска в группированных списках Tom Select строится на трёх уровнях:
searchFieldoptgroupFieldscoreКомбинация этих механизмов формирует гибкую систему, в которой группы могут: