Валидация пользовательского ввода в контексте Tom Select строится на комбинации встроенных механизмов библиотеки, пользовательских фильтров и перехвата событий жизненного цикла элементов. Основная задача — контролировать добавление новых значений, ограничивать формат ввода, предотвращать дубликаты и обеспечивать согласованность данных как на клиентской, так и на серверной стороне.
Tom Select работает с двумя основными типами данных:
Валидация может быть применена на нескольких уровнях:
Ключевые точки расширения:
create — разрешение создания новых элементов;createFilter — фильтрация допустимых значений;onItemAdd — контроль после добавления;onType — обработка ввода пользователя;score — кастомная логика поиска и релевантности.Механизм create управляет возможностью добавления новых
элементов, не присутствующих в списке options.
new TomSelect("#select", {
create: true
});
Более строгая форма валидации:
new TomSelect("#select", {
create: function(input) {
const value = input.trim();
if (value.length < 3) return false;
if (!/^[a-zA-Z0-9_]+$/.test(value)) return false;
return {
value: value,
text: value
};
}
});
В этом варианте функция create заменяет стандартное
поведение и позволяет реализовать полноценную проверку входного значения
перед созданием элемента.
createFilter определяет, какие значения допустимо
превращать в новые элементы.
new TomSelect("#select", {
create: true,
createFilter: function(input) {
return input.length >= 2;
}
});
Расширенный пример с проверкой формата:
new TomSelect("#select", {
create: true,
createFilter: function(input) {
const trimmed = input.trim();
const isValidLength = trimmed.length >= 3;
const matchesPattern = /^[a-z0-9-]+$/i.test(trimmed);
const noSpacesOnly = trimmed !== "";
return isValidLength && matchesPattern && noSpacesOnly;
}
});
Одной из ключевых задач валидации является предотвращение повторного добавления одинаковых значений.
Встроенная логика может быть расширена через
onItemAdd:
new TomSelect("#select", {
create: true,
onItemAdd: function(value) {
const items = this.items;
const duplicates = items.filter(v => v === value);
if (duplicates.length > 1) {
this.removeItem(value, true);
}
}
});
Более корректный подход — блокировка до добавления:
new TomSelect("#select", {
create: function(input) {
const value = input.trim();
if (this.options[value]) {
return false;
}
return {
value,
text: value
};
}
});
Валидация часто включает контроль общего количества выбранных значений.
new TomSelect("#select", {
maxItems: 5,
onItemAdd: function() {
if (this.items.length > 5) {
this.removeItem(this.items[this.items.length - 1]);
}
}
});
Гораздо предпочтительнее использовать встроенный параметр:
new TomSelect("#select", {
maxItems: 5
});
Регулярные выражения позволяют задавать строгие правила для входных данных.
Пример: только email-подобные значения
new TomSelect("#select", {
create: function(input) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(input)) return false;
return {
value: input,
text: input
};
}
});
Пример: ограничение по доменам
const allowedDomains = ["example.com", "site.org"];
new TomSelect("#select", {
create: function(input) {
const domain = input.split("@")[1];
if (!allowedDomains.includes(domain)) {
return false;
}
return {
value: input,
text: input
};
}
});
Для сложных сценариев используется проверка через сервер.
new TomSelect("#select", {
create: function(input, callback) {
fetch(`/validate?value=${encodeURIComponent(input)}`)
.then(res => res.json())
.then(data => {
if (!data.valid) {
callback(false);
return;
}
callback({
value: input,
text: input
});
})
.catch(() => callback(false));
}
});
Асинхронная валидация позволяет:
onType используется для предварительной обработки
пользовательского ввода.
new TomSelect("#select", {
onType: function(str) {
const sanitized = str.replace(/[^a-zA-Z0-9 ]/g, "");
this.setTextboxValue(sanitized);
}
});
Расширенная нормализация:
new TomSelect("#select", {
onType: function(str) {
const normalized = str
.toLowerCase()
.replace(/\s+/g, " ")
.trim();
this.setTextboxValue(normalized);
}
});
onItemAdd позволяет блокировать или корректировать
добавленные значения.
new TomSelect("#select", {
onItemAdd: function(value) {
if (value.length < 3) {
this.removeItem(value);
}
}
});
Дополнительная защита:
new TomSelect("#select", {
onItemAdd: function(value) {
const forbidden = ["admin", "root", "null"];
if (forbidden.includes(value.toLowerCase())) {
this.removeItem(value);
}
}
});
Перед сохранением значений часто требуется унификация формата.
function normalize(value) {
return value
.trim()
.toLowerCase()
.replace(/\s+/g, "_");
}
new TomSelect("#select", {
create: function(input) {
const normalized = normalize(input);
return {
value: normalized,
text: input.trim()
};
}
});
Реальные сценарии требуют объединения нескольких уровней проверки:
new TomSelect("#select", {
create: function(input) {
const value = input.trim();
if (value.length < 3) return false;
if (!/^[a-z0-9-]+$/i.test(value)) return false;
if (this.items.includes(value)) return false;
return {
value,
text: value
};
},
createFilter: function(input) {
return input.trim().length >= 3;
},
onItemAdd: function(value) {
const forbidden = ["test", "demo"];
if (forbidden.includes(value.toLowerCase())) {
this.removeItem(value);
}
}
});
Иногда проверка выполняется не на вводе, а на уровне существующих options.
new TomSelect("#select", {
options: [
{ value: "1", text: "Option 1", disabled: true },
{ value: "2", text: "Option 2" }
]
});
Использование disabled позволяет исключать выбор без
дополнительной логики.
При динамическом обновлении списка возможны рассинхронизации состояния:
new TomSelect("#select", {
onInitialize: function() {
this.refreshOptions(false);
},
onChange: function(value) {
if (!value) return;
if (Array.isArray(value) && value.length === 0) {
this.clear(true);
}
}
});
При использовании remote data источников важно валидировать результаты перед отображением:
new TomSelect("#select", {
load: function(query, callback) {
fetch(`/search?q=${query}`)
.then(res => res.json())
.then(data => {
const filtered = data.filter(item => item.active);
callback(filtered);
})
.catch(() => callback([]));
}
});
Дополнительный уровень защиты включает очистку от потенциально опасных значений:
function sanitize(str) {
return str
.replace(/</g, "")
.replace(/>/g, "")
.replace(/"/g, "");
}
new TomSelect("#select", {
create: function(input) {
const clean = sanitize(input);
return {
value: clean,
text: clean
};
}
});