Структура объекта настроек

Объект настроек в Tom Select представляет собой единый конфигурационный контейнер, определяющий поведение экземпляра: источник данных, правила отображения, обработку ввода, создание элементов, работу с плагинами и событиями. Архитектурно он является плоской структурой с вложенными под-объектами только в отдельных областях (например, render, plugins), что позволяет гибко управлять функциональностью без необходимости наследования или сложной композиции.


Базовая структура конфигурации

Типичная форма объекта настроек включает набор ключей верхнего уровня:

  • options — исходный набор данных
  • items — выбранные значения
  • valueField — поле значения
  • labelField — поле отображения
  • searchField — поля поиска
  • plugins — подключаемые расширения
  • render — шаблоны интерфейса
  • load — функция асинхронной загрузки
  • create — разрешение создания новых элементов
  • onChange, onInitialize и другие callback-и

Каждый из этих ключей влияет на отдельный слой поведения компонента.


Поля идентификации данных

valueField, labelField, optgroupField

valueField: "id",
labelField: "title",
optgroupField: "category"
  • valueField определяет уникальный идентификатор элемента
  • labelField задаёт отображаемый текст
  • optgroupField формирует группы опций

Эти поля являются фундаментом внутреннего сопоставления данных. При отсутствии явной настройки используется стандартная логика поиска ключей value и text, что может приводить к неоднозначности при нестандартных структурах данных.


options и items

options

options: [
  { id: 1, title: "JavaScript" },
  { id: 2, title: "TypeScript" }
]

options содержит полный список доступных элементов. Структура массива не ограничена, но должна соответствовать заданным valueField и labelField.

items

items: [1]

items задаёт начально выбранные значения. Внутренне Tom Select синхронизирует их с valueField, а не с объектами целиком, что позволяет хранить компактные значения без дублирования данных.


Поиск и фильтрация

searchField

searchField: ["title", "description"]

Массив полей, по которым выполняется поиск. По умолчанию используется только labelField.

weight и кастомная фильтрация

Внутренний механизм поиска основан на сравнении строк с нормализацией регистра. При необходимости поведение переопределяется через кастомные обработчики или плагины, влияющие на стратегию ранжирования.


Асинхронная загрузка данных

load

load: function(query, callback) {
  fetch(`/api/items?q=${query}`)
    .then(res => res.json())
    .then(data => callback(data));
}

Функция load активируется при вводе пользователя и отсутствии подходящих локальных опций. Основные особенности:

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

Внутренне результаты автоматически маппируются через valueField и labelField.


Создание новых элементов

create

create: true

Разрешает добавление пользовательских значений, отсутствующих в options.

create как функция

create: function(input) {
  return {
    id: input,
    title: input
  };
}

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

createOnBlur

createOnBlur: true

Автоматически создаёт элемент при потере фокуса, если введённое значение не найдено.

createFilter

createFilter: function(input) {
  return input.length > 2;
}

Фильтр определяет допустимость создания нового элемента.


Шаблоны отображения render

Объект render управляет HTML-структурой интерфейса без вмешательства в логику данных.

Основные шаблоны

render: {
  option: function(data, escape) {
    return `<div>${escape(data.title)}</div>`;
  },
  item: function(data, escape) {
    return `<div>${escape(data.title)}</div>`;
  },
  optgroup_header: function(data, escape) {
    return `<div class="group">${escape(data.label)}</div>`;
  }
}

Особенности render

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

Плагины

plugins

plugins: {
  remove_button: {},
  dropdown_input: {}
}

Или сокращённая форма:

plugins: ["remove_button", "dropdown_input"]

Структура допускает как булевую активацию, так и передачу конфигурации плагина через объект.


Обработка событий

События задаются прямо в объекте настроек.

onInitialize

onInitialize: function() {
  console.log("initialized");
}

onChange

onChange: function(value) {
  console.log(value);
}

onItemAdd и onItemRemove

onItemAdd: function(value) {},
onItemRemove: function(value) {}

События синхронизированы с внутренним состоянием компонента и вызываются после завершения соответствующих операций.


Поведение выбора и ограничений

maxItems

maxItems: 3

Ограничивает количество выбранных элементов. При превышении лимита новые выборы блокируются без ошибок.

persist

persist: true

Определяет сохранение созданных элементов в списке options.

delimiter

delimiter: ","

Используется при работе с текстовыми значениями и сериализацией множественного выбора.


Полный пример структуры настроек

{
  valueField: "id",
  labelField: "title",
  searchField: ["title", "tags"],

  options: [
    { id: 1, title: "JavaScript", tags: "frontend" },
    { id: 2, title: "Node.js", tags: "backend" }
  ],

  items: [1],

  maxItems: 2,
  create: true,
  createOnBlur: true,
  persist: false,

  load: function(query, callback) {
    fetch("/api?q=" + query)
      .then(r => r.json())
      .then(callback);
  },

  render: {
    option: function(data, escape) {
      return `<div>${escape(data.title)}</div>`;
    },
    item: function(data, escape) {
      return `<span>${escape(data.title)}</span>`;
    }
  },

  plugins: ["remove_button"],

  onChange: function(value) {
    console.log(value);
  }
}

Внутренняя согласованность структуры

Объект настроек Tom Select проектируется как декларативная схема, в которой:

  • данные отделены от представления (options vs render)
  • поведение отделено от состояния (create, load, maxItems)
  • расширения подключаются без изменения ядра (plugins)
  • взаимодействие контролируется событиями (onChange, onItemAdd)

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