По умолчанию библиотека Choices.js выполняет поиск по тексту
отображаемого элемента (label). Такой механизм подходит для
простых списков, однако в реальных интерфейсах часто требуется
фильтрация сразу по нескольким свойствам:
Особенно важен многопольный поиск при работе:
Внутри Choices.js поиск работает через параметр
searchFields.
Пример стандартной настройки:
const choices = new Choices('#users', {
searchEnabled: true,
searchFields: ['label', 'value']
});
Массив searchFields определяет, по каким свойствам
объекта выполняется поиск.
Каждый элемент списка может содержать множество полей:
const users = [
{
value: 'u1',
label: 'Александр Петров',
email: 'alex@example.com',
department: 'Разработка',
role: 'Frontend'
},
{
value: 'u2',
label: 'Мария Иванова',
email: 'maria@example.com',
department: 'Маркетинг',
role: 'SEO'
}
];
Самый распространённый вариант:
const choices = new Choices('#users', {
searchEnabled: true,
searchFields: ['label', 'value']
});
Теперь строка поиска будет проверять:
Choices.js поддерживает поиск по произвольным свойствам объекта.
const users = [
{
value: '1',
label: 'Иван Сидоров',
customProperties: {
email: 'ivan@example.com',
city: 'Москва',
department: 'Backend'
}
},
{
value: '2',
label: 'Анна Козлова',
customProperties: {
email: 'anna@example.com',
city: 'Санкт-Петербург',
department: 'UI/UX'
}
}
];
const choices = new Choices('#users', {
choices: users,
searchEnabled: true,
searchFields: [
'label',
'value',
'customProperties.email',
'customProperties.city',
'customProperties.department'
]
});
Теперь поиск работает по:
<select id="employees"></select>
const employees = [
{
value: 'emp-001',
label: 'Андрей Волков',
customProperties: {
email: 'volkov@example.com',
department: 'Backend',
position: 'Senior Developer',
city: 'Алматы'
}
},
{
value: 'emp-002',
label: 'Ольга Смирнова',
customProperties: {
email: 'smirnova@example.com',
department: 'Design',
position: 'UI Designer',
city: 'Астана'
}
},
{
value: 'emp-003',
label: 'Максим Орлов',
customProperties: {
email: 'orlov@example.com',
department: 'DevOps',
position: 'System Engineer',
city: 'Караганда'
}
}
];
const choices = new Choices('#employees', {
choices: employees,
searchEnabled: true,
searchFields: [
'label',
'value',
'customProperties.email',
'customProperties.department',
'customProperties.position',
'customProperties.city'
]
});
Если пользователь вводит:
backend
будут найдены элементы, у которых:
customProperties.department === 'Backend'
Если вводится:
караганда
найдётся запись:
city: 'Караганда'
Если вводится:
smirnova@example.com
поиск выполнится по email.
Часто требуется искать не только по отображаемому тексту, но и по служебной информации.
Пример:
{
value: 'prd-001',
label: 'Ноутбук Lenovo',
customProperties: {
sku: 'LEN-15-8842',
barcode: '220000113344',
vendor: 'Lenovo'
}
}
Настройка:
searchFields: [
'label',
'customProperties.sku',
'customProperties.barcode',
'customProperties.vendor'
]
Теперь пользователь может искать:
const products = [
{
value: '1',
label: 'iPhone 15',
customProperties: {
tags: 'apple smartphone ios'
}
},
{
value: '2',
label: 'Galaxy S24',
customProperties: {
tags: 'samsung android smartphone'
}
}
];
const choices = new Choices('#products', {
choices: products,
searchEnabled: true,
searchFields: [
'label',
'customProperties.tags'
]
});
Теперь поиск по слову:
android
вернёт Samsung.
Choices.js лучше работает со строками, поэтому массив рекомендуется преобразовывать заранее.
tags: ['apple', 'smartphone', 'ios']
tags: 'apple smartphone ios'
Для повышения качества поиска данные часто подготавливаются заранее.
const products = apiData.map(item => ({
value: item.id,
label: item.name,
customProperties: {
searchText: `
${item.name}
${item.category}
${item.vendor}
${item.tags.join(' ')}
${item.article}
`.toLowerCase()
}
}));
Иногда вместо множества searchFields удобнее создать
одно поле:
searchFields: ['customProperties.searchText']
Это особенно эффективно:
const users = [
{
value: '1',
label: 'Алексей',
customProperties: {
searchText: 'алексей frontend react typescript москва'
}
},
{
value: '2',
label: 'Елена',
customProperties: {
searchText: 'елена design figma ui ux минск'
}
}
];
const choices = new Choices('#users', {
choices: users,
searchEnabled: true,
searchFields: ['customProperties.searchText']
});
При работе с тысячами элементов поиск может замедляться.
Основные причины:
searchFields;Плохо:
searchFields: [
'label',
'value',
'customProperties.email',
'customProperties.city',
'customProperties.phone',
'customProperties.position',
'customProperties.department',
'customProperties.description'
]
Лучше:
searchFields: ['customProperties.searchText']
Хорошая практика:
searchText: text.toLowerCase()
const choices = new Choices('#users', {
searchResultLimit: 20
});
Для очень больших наборов данных лучше выполнять поиск на сервере.
const choices = new Choices('#users', {
searchEnabled: true
});
document.querySelector('#users')
.addEventListener('search', async (event) => {
const query = event.detail.value;
const response = await fetch(`/api/users?q=${query}`);
const data = await response.json();
choices.clearChoices();
choices.setChoices(
data,
'value',
'label',
true
);
});
Для кириллицы полезно приводить данные к единому регистру.
searchText: `
${item.name}
${item.city}
`.toLowerCase()
Choices.js автоматически выполняет case-insensitive поиск, однако единая нормализация данных уменьшает вероятность ошибок.
Числовые значения рекомендуется хранить как строки.
id: 10025
id: '10025'
{
value: '1',
label: 'Монитор ASUS',
customProperties: {
article: 'AS-9981-KZ'
}
}
Настройка:
searchFields: [
'label',
'customProperties.article'
]
Choices.js использует Fuse.js для нечёткого поиска.
Дополнительная настройка:
const choices = new Choices('#products', {
searchEnabled: true,
searchFields: [
'label',
'customProperties.searchText'
],
fuseOptions: {
threshold: 0.3
}
});
threshold: 0.1
threshold: 0.6
const choices = new Choices('#cities', {
searchEnabled: true,
searchFields: [
'label',
'customProperties.searchText'
],
fuseOptions: {
threshold: 0.4,
distance: 100
}
});
fuseOptions: {
includeScore: true
}
Позволяет получать оценку релевантности совпадения.
При очень сложных объектах рекомендуется избегать глубоко вложенных структур:
Плохо:
customProperties.meta.department.name
Лучше:
customProperties.department
searchFields: ['customProperties.phone']
Если phone отсутствует у части элементов, возможны
проблемы с качеством поиска.
tags: ['frontend', 'react']
Предпочтительнее:
tags: 'frontend react'
searchFields: [
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h'
]
Такой подход ухудшает производительность.
Наиболее стабильная схема:
customProperties: {
searchText: 'единая поисковая строка'
}
Преимущества:
Сервер может сразу возвращать готовое поисковое поле.
[
{
"value": "1",
"label": "Александр",
"customProperties": {
"searchText": "александр backend nodejs postgres алматы"
}
}
]
Распространённая схема:
setChoices().customProperties: {
searchText: `
notebook ноутбук laptop
computer компьютер pc
`
}
Такой подход позволяет искать:
customProperties: {
searchText: 'frontend frontend developer fe'
}
Теперь поиск:
fe
тоже вернёт результат.
Полное отключение поиска:
searchChoices: false
При многопольной фильтрации параметр должен быть включён:
searchChoices: true
Многопольный поиск особенно полезен для:
<select multiple></select>
Поскольку пользователь может искать элементы по:
const choices = new Choices('#items', {
searchEnabled: true,
searchFields: [
'customProperties.searchText'
],
fuseOptions: {
threshold: 0.3
},
searchResultLimit: 30
});
Формирование данных:
customProperties: {
searchText: `
${name}
${category}
${vendor}
${tags}
${article}
`.toLowerCase()
}
Такой подход обеспечивает: