Сериализация значений

Работа с библиотекой Slim Select в JavaScript неизбежно приводит к необходимости управления данными, которые отображаются в пользовательском интерфейсе и передаются между слоями приложения. Одним из ключевых аспектов является сериализация значений — процесс преобразования выбранных опций в формат, пригодный для хранения, передачи на сервер или дальнейшей обработки в коде.


Базовая модель данных и роль сериализации

Внутренняя модель Slim Select строится вокруг HTML <select> и массива объектов опций, где каждая опция имеет как минимум:

  • text — отображаемое значение
  • value — фактическое значение, используемое в логике приложения
  • дополнительные поля (опционально): data-*, группы, состояния

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

Основные сценарии:

  • отправка формы на сервер
  • сохранение состояния интерфейса
  • синхронизация с состоянием приложения (state management)
  • восстановление выбранных значений при повторной инициализации

Получение значений из Slim Select

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

const select = new SlimSelect({
  select: '#example'
});

const values = select.getSelected();

Метод getSelected() возвращает:

  • строку, если single режим
  • массив строк, если multiple режим

Это уже частично сериализованная форма, но она остаётся примитивной и не содержит контекста опций.


Преобразование в структурированные объекты

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

Исходная структура:

[
  { text: 'Apple', value: 'apple', price: 100 },
  { text: 'Banana', value: 'banana', price: 80 }
]

После выбора:

['apple', 'banana']

Задача сериализации — восстановить полные объекты:

const data = select.getData();

const selectedObjects = select.getSelected().map(value => {
  return data.find(item => item.value === value);
});

Такой подход позволяет формировать расширенную модель:

[
  { text: 'Apple', value: 'apple', price: 100 },
  { text: 'Banana', value: 'banana', price: 80 }
]

Сериализация в JSON-формат

Для передачи данных через HTTP или сохранения в хранилище применяется JSON-сериализация.

Типичный сценарий:

const selected = select.getSelected();
const payload = JSON.stringify(selected);

В результате получается строка:

["apple","banana"]

Однако более сложные приложения требуют сохранения контекста:

const data = select.getData();

const payload = JSON.stringify(
  select.getSelected().map(value => {
    const item = data.find(i => i.value === value);
    return {
      value: item.value,
      text: item.text
    };
  })
);

Результат:

[
  { "value": "apple", "text": "Apple" },
  { "value": "banana", "text": "Banana" }
]

Десериализация и восстановление состояния

Сериализация всегда предполагает обратный процесс. В Slim Select восстановление состояния выполняется через метод setSelected.

select.setSelected(['apple', 'banana']);

После вызова:

  • DOM синхронизируется
  • внутреннее состояние обновляется
  • UI отражает выбранные элементы

Если данные сериализованы в объектной форме, требуется предварительное извлечение value:

const saved = [
  { value: 'apple', text: 'Apple' },
  { value: 'banana', text: 'Banana' }
];

select.setSelected(saved.map(item => item.value));

Сериализация при работе с multiple select

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

Основные особенности:

  • порядок значений сохраняется
  • дубликаты исключаются
  • пустой выбор возвращает пустой массив
const values = select.getSelected();

Пример результата:

["apple", "banana", "cherry"]

При необходимости можно дополнительно нормализовать данные:

const normalized = [...new Set(select.getSelected())];

Обработка кастомных данных (data-* атрибуты)

Slim Select поддерживает привязку пользовательских данных через data-* атрибуты <option>.

Пример:

<option value="apple" data-price="100" data-stock="12">Apple</option>

При сериализации стандартный getSelected() не включает эти данные, поэтому требуется расширение:

const data = select.getData();

const serialized = select.getSelected().map(value => {
  const item = data.find(i => i.value === value);

  return {
    value: item.value,
    text: item.text,
    price: item.data.price,
    stock: item.data.stock
  };
});

Такой подход превращает простую строковую модель в полноценный объект доменной логики.


Сериализация при динамическом обновлении данных

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

select.setData([
  { text: 'Apple', value: 'apple' },
  { text: 'Banana', value: 'banana' }
]);

важно учитывать, что сериализованные значения могут устаревать.

Проблема возникает, если:

  • ранее сохранённые значения отсутствуют в новом списке
  • структура опций изменилась
  • изменились value ключи

Решение заключается в валидации перед восстановлением:

const data = select.getData().map(i => i.value);

const validValues = savedValues.filter(v => data.includes(v));

select.setSelected(validValues);

Сериализация событий изменения

Slim Select предоставляет событие onChange, которое можно использовать для постоянной сериализации состояния:

new SlimSelect({
  select: '#example',
  onChange: (info) => {
    const serialized = JSON.stringify(info);
  }
});

В зависимости от режима:

  • single → объект
  • multiple → массив объектов

Это позволяет хранить актуальное состояние без дополнительного вызова getSelected().


Инкрементальная сериализация

В сложных интерфейсах сериализация может выполняться не целиком, а по изменению состояния.

Пример отслеживания добавления и удаления:

let previous = [];

select.onCha nge = (info) => {
  const current = select.getSelected();

  const added = current.filter(x => !previous.includes(x));
  const removed = previous.filter(x => !current.includes(x));

  previous = current;
};

Такой подход используется в:

  • больших формах
  • фильтрах
  • системах с серверной синхронизацией

Форматы сериализации и их применение

В зависимости от архитектуры приложения применяются разные форматы:

1. Примитивный массив

["a","b","c"]

Используется для API и простых форм.

2. Массив объектов

[
  {"value":"a","text":"A"}
]

Используется для UI-состояний.

3. Расширенный доменный формат

[
  {"value":"a","text":"A","meta":{"price":100}}
]

Используется в сложной бизнес-логике.


Потенциальные проблемы сериализации

При работе с Slim Select часто возникают следующие проблемы:

  • потеря связей между value и метаданными
  • несогласованность данных при динамическом обновлении
  • дублирование значений при ручной сериализации
  • рассинхронизация UI и сохранённого состояния

Корректная стратегия требует:

  • использования getData() как источника истины
  • отказа от хранения только text
  • строгой валидации value при десериализации

Использование сериализации в архитектуре приложения

Сериализация в контексте Slim Select часто становится частью более широкой архитектуры:

  • UI слой → SlimSelect управляет отображением
  • Service слой → преобразует данные в DTO
  • API слой → принимает JSON
  • State слой → хранит сериализованное состояние

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