Шаблон для выбранных элементов

В библиотеке Choices.js визуальное представление выбранных элементов (selected items) отделено от логики хранения данных. Это позволяет гибко настраивать интерфейс: изменять структуру HTML, добавлять дополнительные элементы, управлять отображением текста, иконок, меток и интерактивных элементов внутри выбранных значений.

Шаблонизация выбранных элементов основана на наборе функций callback, передаваемых в конфигурацию экземпляра. Каждая функция отвечает за формирование DOM-структуры одного элемента. Наиболее важной среди них является callbackOnCreateTemplates, которая переопределяет стандартные шаблоны рендеринга.


Базовая архитектура шаблонов выбранных элементов

Внутри Choices.js каждый выбранный элемент представляет собой объект, который преобразуется в DOM-узел. Этот процесс происходит через систему шаблонов, где ключевую роль играет функция генерации HTML-структуры.

Основная цепочка выглядит следующим образом:

  • данные элемента (value, label, custom properties)
  • обработка состояния (disabled, highlighted, selected)
  • передача в шаблонную функцию
  • генерация DOM-элемента
  • вставка в контейнер выбранных элементов

Ключевое место занимает объект templates, который переопределяется при инициализации.


Переопределение шаблонов через callbackOnCreateTemplates

Функция callbackOnCreateTemplates возвращает объект, содержащий методы генерации UI-элементов. Каждый метод отвечает за конкретный тип элемента, включая выбранные значения.

Структура:

const choices = new Choices(element, {
  callbackOnCreateTemplates: function (template) {
    return {
      item: (classNames, data) => {
        return template(`
          <div class="${classNames.item} ${data.highlighted ? classNames.highlightedState : ''}" data-item data-id="${data.id}" data-value="${data.value}">
            <span class="choices__item-text">${data.label}</span>
          </div>
        `);
      }
    };
  }
});

В данном примере шаблон item полностью заменяет стандартный рендер выбранного элемента.


Структура объекта данных выбранного элемента

Каждый элемент, передаваемый в шаблон, содержит набор стандартных свойств:

  • id — уникальный идентификатор внутри списка
  • value — значение элемента
  • label — отображаемый текст
  • customProperties — пользовательские метаданные
  • active — состояние активности
  • highlighted — состояние подсветки
  • disabled — недоступность элемента

Использование этих свойств позволяет строить динамические шаблоны, учитывающие состояние элемента без дополнительной логики.


Кастомизация структуры выбранного элемента

Наиболее распространённый сценарий — расширение выбранного элемента дополнительными визуальными компонентами.

Пример добавления иконки и бейджа:

item: (classNames, data) => {
  return template(`
    <div class="${classNames.item}" data-item data-id="${data.id}" data-value="${data.value}">
      <span class="choices__icon"></span>
      <span class="choices__label">${data.label}</span>
      <span class="choices__badge">${data.customProperties?.badge || ''}</span>
    </div>
  `);
}

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


Работа с удалением выбранных элементов

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

removeItemButton: (classNames) => {
  return template(`
    <button type="button" class="${classNames.button}" data-button>
      <svg class="icon-close"></svg>
    </button>
  `);
}

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


Использование customProperties в шаблонах

Поле customProperties предоставляет возможность расширять стандартную модель данных. Оно особенно полезно при работе с тегами, пользователями, категориями или сложными объектами.

Пример использования:

item: (classNames, data) => {
  const color = data.customProperties?.color || 'default';

  return template(`
    <div class="${classNames.item} item--${color}" data-value="${data.value}">
      <span>${data.label}</span>
    </div>
  `);
}

Таким образом можно внедрять семантические стили без изменения логики компонента.


Управление состояниями внутри шаблонов

Состояния элементов напрямую влияют на их визуальное представление. Наиболее важные состояния:

  • выделение (highlighted)
  • активность (active)
  • отключение (disabled)

Пример обработки:

item: (classNames, data) => {
  const stateClass = data.disabled
    ? classNames.itemDisabled
    : data.highlighted
      ? classNames.highlightedState
      : classNames.itemSelectable;

  return template(`
    <div class="${classNames.item} ${stateClass}" data-value="${data.value}">
      ${data.label}
    </div>
  `);
}

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


Вложенные элементы внутри выбранного элемента

Choices.js допускает создание сложных шаблонов, где выбранный элемент содержит дополнительные интерактивные блоки.

Пример:

item: (classNames, data) => {
  return template(`
    <div class="${classNames.item}">
      <div class="item-content">
        <span class="title">${data.label}</span>
        <span class="meta">${data.customProperties?.description || ''}</span>
      </div>
      <div class="item-actions">
        <button data-action="edit"></button>
      </div>
    </div>
  `);
}

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


Интеграция с динамическими данными

При работе с API или динамическими источниками данных шаблон должен учитывать возможное отсутствие части свойств.

item: (classNames, data) => {
  const label = data.label || data.value || 'undefined';

  return template(`
    <div class="${classNames.item}" data-value="${data.value}">
      ${label}
    </div>
  `);
}

Такая защита предотвращает некорректный рендеринг при неполных данных.


Стилизация через классы Choices.js

Библиотека предоставляет набор системных классов, которые автоматически применяются к элементам:

  • choices__item
  • choices__item--selectable
  • choices__item--disabled
  • choices__item--highlighted

Использование этих классов внутри шаблонов обеспечивает совместимость с внутренней логикой управления состояниями.


Комбинирование шаблонов с кастомными событиями

Шаблон выбранного элемента может включать атрибуты для последующей обработки событий:

item: (classNames, data) => {
  return template(`
    <div class="${classNames.item}" data-action="select" data-id="${data.id}">
      ${data.label}
    </div>
  `);
}

Это позволяет реализовать внешние обработчики кликов без изменения внутренней логики Choices.js.


Ограничения шаблонизации

При глубокой кастомизации следует учитывать архитектурные ограничения:

  • шаблоны не управляют состоянием напрямую
  • логика фильтрации и выбора остаётся внутри библиотеки
  • чрезмерная вложенность может ухудшить производительность
  • повторное создание DOM-структур происходит при каждом изменении состояния

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


Организация переиспользуемых шаблонов

Для масштабных проектов шаблоны часто выносятся в отдельные функции:

function createItemTemplate(template, classNames) {
  return (data) => {
    return template(`
      <div class="${classNames.item}">
        ${data.label}
      </div>
    `);
  };
}

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