Автокомплит с подсказками

Механизм автодополнения в Tom Select строится вокруг поискового поля, которое фильтрует элементы массива и отображает подходящие совпадения по мере ввода текста. Базовая конфигурация включает указание поля поиска и списка значений:

new TomSelect("#select", {
  options: [
    { id: 1, title: "JavaScript" },
    { id: 2, title: "TypeScript" },
    { id: 3, title: "Python" },
    { id: 4, title: "Go" }
  ],
  labelField: "title",
  valueField: "id",
  searchField: "title",
  create: false
});

Поиск выполняется по полю searchField, где допускается указание массива ключей. Это позволяет расширить логику совпадений:

searchField: ["title", "description"]

Фильтрация осуществляется встроенным алгоритмом поиска, использующим нормализацию строк и сравнение подстрок. Поведение можно модифицировать через кастомные функции поиска и сортировки.


Управление алгоритмом поиска

Tom Select позволяет переопределять механизм фильтрации через score и sortField. Это используется при необходимости изменить релевантность результатов.

new TomSelect("#select", {
  options: data,
  labelField: "name",
  valueField: "id",
  searchField: "name",

  score: function(search) {
    return function(item) {
      const value = item.name.toLowerCase();
      const query = search.toLowerCase();
      return value.includes(query) ? 1 : 0;
    };
  }
});

Функция score возвращает числовую оценку релевантности. Чем выше значение, тем выше позиция элемента в списке.

Сортировка дополняет механизм ранжирования:

sortField: {
  field: "name",
  direction: "asc"
}

Асинхронный автокомплит

Для динамической загрузки данных используется опция load. Она активируется при вводе текста и позволяет получать подсказки с сервера.

new TomSelect("#select", {
  valueField: "id",
  labelField: "title",
  searchField: "title",

  load: function(query, callback) {
    if (!query.length) return callback();

    fetch(`/api/search?q=${encodeURIComponent(query)}`)
      .then(response => response.json())
      .then(json => callback(json))
      .catch(() => callback());
  }
});

Запрос выполняется только при наличии текста, что снижает нагрузку на сервер. Результат передаётся через callback, который обновляет список опций.


Кэширование результатов поиска

При частых запросах к API используется кэширование, позволяющее избегать повторных запросов:

const cache = {};

new TomSelect("#select", {
  load: function(query, callback) {
    if (cache[query]) {
      callback(cache[query]);
      return;
    }

    fetch(`/api/search?q=${query}`)
      .then(res => res.json())
      .then(data => {
        cache[query] = data;
        callback(data);
      })
      .catch(() => callback());
  }
});

Кэш хранит результаты по ключу запроса, что уменьшает задержки при повторном вводе одинаковых символов.


Форматирование отображения подсказок

Отображение элементов списка управляется через шаблоны render. Это позволяет кастомизировать внешний вид автокомплита.

new TomSelect("#select", {
  labelField: "title",
  valueField: "id",
  searchField: "title",

  render: {
    option: function(data, escape) {
      return `
        <div>
          <span class="title">${escape(data.title)}</span>
          <span class="meta">${escape(data.category)}</span>
        </div>
      `;
    },

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

Функция escape применяется для защиты от внедрения HTML-кода. Разделение option и item позволяет отдельно контролировать список подсказок и выбранные значения.


Подсветка совпадений

Подсветка введённого текста реализуется вручную через обработку строки запроса:

render: {
  option: function(data, escape) {
    const query = this.inputValue || "";
    const regex = new RegExp(query, "i");

    const highlighted = data.title.replace(regex, function(match) {
      return `<strong>${match}</strong>`;
    });

    return `<div>${highlighted}</div>`;
  }
}

Подход зависит от текущего значения input, которое доступно через внутреннее состояние компонента.


Управление вводом и события поиска

Tom Select предоставляет набор событий, позволяющих контролировать поведение автокомплита:

new TomSelect("#select", {
  onType: function(str) {
    console.log("Ввод:", str);
  },

  onSearch: function(query) {
    console.log("Поиск:", query);
  },

  onDropdownOpen: function() {
    console.log("Список открыт");
  }
});

Событие onType вызывается при каждом изменении поля ввода. Это позволяет реализовать внешние фильтры или аналитику ввода.


Ограничение частоты запросов (debounce)

При работе с удалёнными источниками данных применяется задержка между запросами:

function debounce(fn, delay) {
  let timeout;
  return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => fn.apply(this, args), delay);
  };
}

const loadData = debounce(function(query, callback) {
  fetch(`/api?q=${query}`)
    .then(r => r.json())
    .then(callback);
}, 300);

Интеграция с Tom Select:

new TomSelect("#select", {
  load: loadData
});

Задержка предотвращает отправку запроса на каждый символ и снижает нагрузку на сервер.


Ограничение количества результатов

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

new TomSelect("#select", {
  maxOptions: 10
});

Это особенно важно при больших наборах данных, где количество совпадений может быть высоким.


Создание новых элементов через автокомплит

Функция create позволяет добавлять новые значения, если совпадений не найдено:

new TomSelect("#select", {
  create: true,
  createFilter: function(input) {
    return input.length > 2;
  }
});

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


Кастомная логика поиска

Для сложных структур данных применяется переопределение фильтрации через filter:

new TomSelect("#select", {
  filter: function(item, query) {
    return item.title.toLowerCase().startsWith(query.toLowerCase());
  }
});

Такая логика позволяет реализовать строгий префиксный поиск, игнорируя стандартное поведение подстрочного совпадения.


Синхронизация состояния выбора

Выбранные элементы доступны через API экземпляра:

const control = new TomSelect("#select");

control.setValue(2);
control.addOption({ id: 5, title: "Rust" });
control.refreshOptions();

Изменение состояния напрямую влияет на отображение автокомплита и список доступных подсказок.


Работа с большими наборами данных

При значительном объёме данных используется комбинация серверной фильтрации и минимального локального кэширования. Основной принцип заключается в передаче ответственности поиска на сервер и получении уже отфильтрованных результатов.

new TomSelect("#select", {
  loadThrottle: 300,
  firstUrl: function(query) {
    return `/api/search?q=${encodeURIComponent(query)}`;
  }
});

Подобный подход уменьшает объём передаваемых данных и ускоряет отклик интерфейса за счёт сокращения локальных вычислений.