Доступ к данным в шаблонах

В Slim Select структура данных, доступная внутри шаблонов, строится вокруг нормализованного объекта опции. Любой кастомный рендер (option, selected, group label) получает единый контекст, в котором исходные данные уже преобразованы в предсказуемую форму. Это позволяет строить сложные интерфейсы без необходимости обращаться к DOM или парсить HTML вручную.

Базовая структура объекта опции

Каждая опция внутри Slim Select представляется объектом с набором стандартных полей:

  • value — значение, отправляемое в форму
  • text — отображаемый текст
  • html — HTML-разметка (если используется кастомный контент)
  • disabled — состояние недоступности
  • selected — текущее состояние выбора
  • placeholder — флаг плейсхолдера
  • data — произвольные пользовательские данные

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

new SlimSelect({
  select: '#select',
  data: [
    {
      text: 'Apple',
      value: 'apple',
      data: {
        color: 'red',
        calories: 52,
        icon: '?'
      }
    },
    {
      text: 'Banana',
      value: 'banana',
      data: {
        color: 'yellow',
        calories: 96,
        icon: '?'
      }
    }
  ]
});

В шаблонах эти данные доступны напрямую через объект опции.


Доступ к данным в шаблоне option

Шаблон option отвечает за отображение элемента в выпадающем списке. В него передаётся объект с полной структурой опции.

new SlimSelect({
  select: '#select',
  settings: {
    template: {
      option: (option) => {
        return `
          <div class="option">
            <span class="icon">${option.data.icon}</span>
            <span class="title">${option.text}</span>
            <span class="meta">${option.data.calories} kcal</span>
          </div>
        `;
      }
    }
  }
});

Доступ к данным происходит через:

  • option.text — основной текст
  • option.value — идентификатор
  • option.data.* — пользовательские поля

Использование data позволяет полностью отделить визуальное представление от логики данных.


Работа с отсутствующими полями

При работе с динамическими источниками данных структура data может быть неполной. В таких случаях важно учитывать отсутствие свойств.

template: {
  option: (option) => {
    const icon = option.data?.icon || '';
    const subtitle = option.data?.subtitle || 'Нет описания';

    return `
      <div class="option">
        <span>${icon}</span>
        <div>
          <div>${option.text}</div>
          <small>${subtitle}</small>
        </div>
      </div>
    `;
  }
}

Использование optional chaining и fallback-значений предотвращает разрушение шаблона при неполных данных.


Передача сложных структур в data

Поле data не ограничивается примитивами. В него могут быть вложенные структуры, включая массивы и объекты.

{
  text: 'Product A',
  value: 'a',
  data: {
    stats: {
      rating: 4.7,
      reviews: 1240
    },
    tags: ['popular', 'discount'],
    availability: {
      stock: 15,
      warehouse: 'EU'
    }
  }
}

Доступ в шаблоне:

template: {
  option: (option) => {
    return `
      <div>
        <div>${option.text}</div>
        <div>Rating: ${option.data.stats.rating}</div>
        <div>Reviews: ${option.data.stats.reviews}</div>
        <div>Stock: ${option.data.availability.stock}</div>
      </div>
    `;
  }
}

Такой подход превращает Slim Select в слой представления поверх произвольной бизнес-модели.


Использование HTML в данных

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

{
  text: 'Server 1',
  value: 'srv1',
  html: '<strong>Server 1</strong> <em>(active)</em>',
  data: {
    status: 'active'
  }
}

В шаблоне можно переключаться между text и html:

template: {
  option: (option) => {
    return `
      <div class="option">
        ${option.html || option.text}
      </div>
    `;
  }
}

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


Доступ к данным выбранного элемента

Шаблон выбранного значения (selected) работает с тем же объектом опции, что и option, но используется для отображения в закрытом состоянии селекта.

new SlimSelect({
  select: '#select',
  settings: {
    template: {
      selected: (option) => {
        return `
          <div class="selected">
            <span>${option.data.icon}</span>
            <span>${option.text}</span>
          </div>
        `;
      }
    }
  }
});

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


Различие между text и data.text

Частая ошибка при проектировании данных — дублирование информации в text и data.text. В Slim Select:

  • text используется системой как основной источник отображения
  • data предназначено для расширения, а не замены базовых полей

Корректная модель:

{
  text: 'Москва',
  value: 'moscow',
  data: {
    timezone: 'UTC+3',
    population: 12500000
  }
}

Некорректная модель:

{
  text: 'Москва',
  data: {
    text: 'Москва'
  }
}

Дублирование приводит к избыточной вложенности и усложняет шаблоны.


Условная логика внутри шаблонов

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

template: {
  option: (option) => {
    const isHighRated = option.data.rating > 4;

    return `
      <div class="option ${isHighRated ? 'highlight' : ''}">
        <span>${option.text}</span>
        <span>${option.data.rating}</span>
      </div>
    `;
  }
}

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


Нормализация данных перед передачей в Slim Select

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

const apiData = [
  { name: 'Item 1', id: 1, meta: { score: 10 } },
  { name: 'Item 2', id: 2, meta: { score: 20 } }
];

const normalized = apiData.map(item => ({
  text: item.name,
  value: item.id,
  data: {
    score: item.meta.score
  }
}));

new SlimSelect({
  select: '#select',
  data: normalized
});

Такой слой преобразования отделяет API-структуру от UI-структуры, упрощая шаблоны.


Ограничения доступа к данным

Шаблоны Slim Select работают в синхронном контексте и не предназначены для асинхронных операций. Доступные данные должны быть заранее подготовлены.

Недопустимые подходы:

  • HTTP-запросы внутри template-функций
  • изменение состояния приложения из шаблона
  • мутация входного объекта option

Шаблон должен оставаться чистой функцией отображения:

(option) => string

Изоляция данных между опциями

Каждая опция обрабатывается независимо. Изменение option.data внутри одного шаблона не влияет на другие элементы. Это позволяет безопасно использовать общие структуры данных без риска побочных эффектов.

template: {
  option: (option) => {
    option.data.used = true; // нежелательная практика

    return `<div>${option.text}</div>`;
  }
}

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


Использование данных для стилизации

Данные могут напрямую влиять на CSS-классы и визуальное состояние элементов.

template: {
  option: (option) => {
    return `
      <div class="option status-${option.data.status}">
        ${option.text}
      </div>
    `;
  }
}

Где status может принимать значения active, disabled, pending, формируя разные визуальные состояния без изменения логики Slim Select.


Композиция данных для сложных интерфейсов

При построении сложных селектов (категории, товары, пользователи) data становится основным инструментом композиции:

  • метаинформация
  • визуальные индикаторы
  • права доступа
  • статистика
  • вложенные сущности

Пример структуры для пользователя:

{
  text: 'John Doe',
  value: 42,
  data: {
    role: 'admin',
    avatar: '/img/john.png',
    permissions: ['edit', 'delete'],
    activity: {
      lastLogin: '2026-05-25',
      score: 87
    }
  }
}

Шаблон превращается в отображение полноценной карточки сущности, а не просто строки списка.