Tom Select построен вокруг модели выбора элементов, где каждое
добавленное значение попадает в внутренний список items, а
идентификация осуществляется через valueField. Дублирование
возникает не на уровне DOM, а на уровне логики добавления: один и тот же
value может быть повторно добавлен, если не наложены
ограничения в конфигурации или обработчиках событий.
Дублирование чаще всего проявляется в режимах:
plugins: ['remove_button'] при повторном добавлении
через addItemcreate-значения (теги)load), где совпадающие
value приходят повторноaddItem() без проверки
текущего состоянияВнутренняя модель не запрещает дубли сама по себе, если не задана явная логика фильтрации.
Уникальность в Tom Select определяется значением поля:
valueField — ключ уникальностиitems[] — массив выбранных значенийЕсли valueField совпадает, но проверка не реализована,
библиотека может добавить элемент повторно в некоторых сценариях
(особенно при ручном вызове API).
Наиболее прямой способ — проверка перед добавлением:
const control = new TomSelect('#select', {
valueField: 'id',
labelField: 'title',
searchField: 'title',
options: [],
items: []
});
function addUniqueItem(value) {
if (control.items.includes(value)) {
return;
}
control.addItem(value);
}
Такой подход блокирует дубли на уровне API-слоя.
Более централизованная стратегия — контроль через событие:
const control = new TomSelect('#select', {
valueField: 'id',
labelField: 'title',
searchField: 'title',
onItemAdd(value) {
const occurrences = control.items.filter(v => v === value).length;
if (occurrences > 1) {
control.removeItem(value, true);
}
}
});
Здесь реализуется пост-фильтрация, устраняющая повторное добавление.
Если источником данных является фиксированный список:
const options = [
{ id: 1, title: 'Alpha' },
{ id: 2, title: 'Beta' }
];
const control = new TomSelect('#select', {
options: options,
valueField: 'id',
labelField: 'title',
searchField: 'title',
create: false
});
При create: false исключаются пользовательские значения,
что уже снижает риск появления повторов.
Для тегов и пользовательских значений критичен
createFilter:
const control = new TomSelect('#tags', {
create: true,
createFilter: function(input) {
return !this.options.hasOwnProperty(input);
}
});
Здесь используется проверка существования ключа в
options, что предотвращает повторное создание одинаковых
значений.
При load(query, callback) дубликаты часто появляются
из-за повторного возврата одинаковых элементов от сервера:
load: function(query, callback) {
fetch('/api/search?q=' + encodeURIComponent(query))
.then(res => res.json())
.then(data => {
const filtered = data.filter(item => !this.options[item.id]);
callback(filtered);
});
}
Фильтрация по this.options предотвращает повторное
добавление уже существующих элементов.
Дубли могут возникать из-за различий в типах:
"1" и 1"tag" и "tag "Решение — нормализация:
function normalize(value) {
return String(value).trim().toLowerCase();
}
const control = new TomSelect('#select', {
onItemAdd(value) {
const normalized = normalize(value);
const duplicates = control.items.filter(
v => normalize(v) === normalized
);
if (duplicates.length > 1) {
control.removeItem(value, true);
}
}
});
addItem() — основной источник скрытых дубликатов:
function safeAdd(value) {
if (!control.items.includes(value)) {
control.addItem(value, true);
}
}
Флаг silent (второй аргумент) снижает количество
побочных эффектов при массовых операциях.
Дополнительный UX-подход — отключение уже выбранных опций:
onItemAdd: function(value) {
if (this.options[value]) {
this.getOption(value).classList.add('disabled');
}
},
onItemRemove: function(value) {
const opt = this.getOption(value);
if (opt) opt.classList.remove('disabled');
}
Это не технический запрет, но визуально блокирует повторный выбор.
Хотя maxItems не предотвращает дубликаты напрямую, он
ограничивает рост массива:
new TomSelect('#select', {
maxItems: 5
});
При малом лимите вероятность повторов снижается в пользовательских сценариях, но программные дубли остаются возможными.
items.includes — минимальная и надёжнаяonItemAdd фильтрация — централизованный контрольcreateFilter — защита теговload — обязательна при API-данныхКомбинация этих механизмов даёт устойчивую модель уникальности, где каждый слой закрывает отдельный класс источников дублирования.