Ограничение количества выбранных элементов

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

Параметр maxItems как основной механизм ограничения

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

new TomSelect("#select", {
  maxItems: 3
});

При значении 1 компонент фактически превращается в одновыборочный список, аналогичный стандартному <select> без множественного выбора, но с сохранением расширенных возможностей поиска и рендеринга.

new TomSelect("#select", {
  maxItems: 1
});

В случае отсутствия ограничения (maxItems: null) количество выбранных элементов становится неограниченным, что соответствует поведению по умолчанию для мультиселекта.


Поведение интерфейса при достижении лимита

При достижении значения maxItems происходит несколько внутренних изменений состояния:

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

С точки зрения UX это важно, поскольку пользователь не получает явной ошибки, а ограничение проявляется через недоступность действий.


Динамическое управление лимитом

Значение maxItems может быть изменено после инициализации компонента. Для этого используется метод setValue или пересоздание конфигурации через обновление настроек.

const select = new TomSelect("#select", {
  maxItems: 2
});

// изменение логики ограничения
select.settings.maxItems = 5;
select.refreshOptions(false);

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


Контроль через события

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

new TomSelect("#select", {
  maxItems: 3,
  onItemAdd: function(value) {
    if (this.items.length > this.settings.maxItems) {
      this.removeItem(value);
    }
  }
});

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


Политики отклонения новых значений

При превышении лимита возможны разные стратегии обработки:

1. Игнорирование новых значений

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

2. Удаление последнего добавленного значения

onItemAdd: function(value) {
  if (this.items.length > this.settings.maxItems) {
    this.removeItem(this.items[this.items.length - 1]);
  }
}

3. Замена старого значения новым

onItemAdd: function(value) {
  if (this.items.length > this.settings.maxItems) {
    const removed = this.items.shift();
    this.removeItem(removed);
  }
}

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


Ограничение через disable состояния

Помимо maxItems, ограничение может реализовываться через временное отключение компонента. Метод disable() полностью блокирует взаимодействие, включая открытие списка и ввод.

if (select.items.length >= 3) {
  select.disable();
}

Обратное включение осуществляется через enable().

select.enable();

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


Комбинирование с удалением элементов

В мультивыборе часто требуется сохранять возможность удаления даже при достижении лимита. Tom Select сохраняет стандартное поведение удаления тегов независимо от maxItems.

Это позволяет реализовать стратегию «скользящего окна», где пользователь может удалять элементы и добавлять новые до достижения ограничения.


Влияние на async-загрузку и динамические списки

При использовании удалённого источника данных (load), ограничение maxItems влияет только на локальный выбор, но не на загрузку опций.

new TomSelect("#select", {
  maxItems: 2,
  load: function(query, callback) {
    fetch(`/api/search?q=${query}`)
      .then(res => res.json())
      .then(data => callback(data));
  }
});

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


Интеграция с плагинами

Некоторые плагины Tom Select могут изменять поведение ограничения:

  • remove_button усиливает управление удалением элементов;
  • dropdown_input влияет на ввод при достижении лимита;
  • кастомные плагины могут полностью переопределять логику добавления.

При разработке расширений важно учитывать значение maxItems, так как оно остаётся центральным ограничителем состояния выбора.


Состояние items как источник истины

Массив items внутри экземпляра является фактическим источником текущего состояния выбора. Любые ограничения, включая maxItems, в конечном счёте влияют именно на него.

console.log(select.items);

Проверка длины массива используется во всех пользовательских и встроенных механизмах ограничения.


Предиктивное ограничение перед добавлением

Вместо пост-фактум удаления элементов может применяться проверка перед добавлением через shouldAddItem-подобную логику, реализуемую вручную.

onItemAdd: function(value) {
  if (this.items.length > this.settings.maxItems) {
    this.removeItem(value);
    return;
  }
}

Такой подход снижает визуальные артефакты и предотвращает кратковременное превышение лимита.


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

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

onDropdownOpen: function() {
  if (this.items.length >= this.settings.maxItems) {
    this.close();
  }
}

Это предотвращает попытки дальнейшего выбора через интерфейс списка.


Использование кастомных правил ограничения

В ряде случаев фиксированное значение maxItems недостаточно. Тогда применяется вычисляемое ограничение:

new TomSelect("#select", {
  maxItems: 10,
  onItemAdd: function(value) {
    const limit = this.settings.maxItems;
    const dynamicLimit = limit - (this.items.includes("admin") ? 2 : 0);

    if (this.items.length > dynamicLimit) {
      this.removeItem(value);
    }
  }
});

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


Поведение при программном добавлении значений

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

select.addItem("value");

Для строгого контроля используется предварительная проверка:

if (select.items.length < select.settings.maxItems) {
  select.addItem("value");
}

Согласованность состояния при массовых операциях

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

select.setValue(["a", "b", "c", "d"]);

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


Управление визуальной индикацией лимита

Tom Select не отображает ограничение явно, поэтому часто добавляется кастомная индикация:

onItemAdd: function() {
  const remaining = this.settings.maxItems - this.items.length;
  console.log(`Осталось: ${remaining}`);
}

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


Связь ограничения с архитектурой формы

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

В типизированных схемах данных это соответствует массиву с верхней границей длины, где maxItems выступает как клиентское отражение серверного правила валидации.