Валидация пользовательского ввода

Dragula — это легковесная библиотека для реализации функциональности drag-and-drop на веб-страницах. Она обеспечивает простое создание интерактивных интерфейсов, где элементы можно перемещать между контейнерами без необходимости работы с низкоуровневыми событиями мыши и touch-событиями. Dragula особенно удобна для динамических интерфейсов, таких как списки задач, панели управления или интерактивные таблицы.

Инициализация Dragula происходит через вызов функции dragula(containers, options), где containers — массив DOM-элементов или селекторов контейнеров, а options — объект с настройками поведения. Основные параметры, влияющие на работу drag-and-drop, включают:

  • moves — функция, определяющая, какие элементы можно перетаскивать.
  • accepts — функция, определяющая, в какие контейнеры элемент может быть помещен.
  • copy — логический флаг, указывающий, создается ли копия перетаскиваемого элемента.
  • revertOnSpill — откат элемента на исходное место при случайном отпускании вне контейнера.

Настройка правил перетаскивания

Функция moves(el, source, handle, sibling) позволяет гибко ограничивать возможность перетаскивания. Параметры функции:

  • el — перетаскиваемый элемент.
  • source — контейнер, из которого осуществляется перетаскивание.
  • handle — элемент, по которому пользователь кликнул для начала drag.
  • sibling — элемент, перед которым будет вставлен перетаскиваемый элемент, если операция успешна.

Пример ограничения перетаскивания только по специальной «ручке»:

dragula([container1, container2], {
    moves: function(el, source, handle, sibling) {
        return handle.classList.contains('drag-handle');
    }
});

Функция accepts(el, target, source, sibling) управляет логикой попадания элементов в контейнеры. Это позволяет создавать сложные правила, например, запрещать перемещение элементов с определенным классом в определенные контейнеры.

dragula([container1, container2], {
    accepts: function(el, target, source, sibling) {
        return !el.classList.contains('locked');
    }
});

События Dragula и их обработка

Dragula генерирует набор событий, которые позволяют отслеживать жизненный цикл перетаскивания:

  • drag — срабатывает при начале перетаскивания.
  • drop — срабатывает при успешной вставке элемента в контейнер.
  • over — когда элемент наведен над контейнером.
  • out — когда элемент покидает контейнер.
  • cancel — когда перетаскивание отменено.
  • remove — когда элемент удален из контейнера при removeOnSpill: true.

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

drake.on('drop', function(el, target, source, sibling) {
    if (!validateDrop(el, target)) {
        source.insertBefore(el, sibling); // возвращаем элемент обратно
    }
});

Валидация пользовательского ввода через Dragula

Основная задача Dragula в контексте валидации — это предотвращение некорректного перемещения элементов и обеспечение целостности данных. Валидация может выполняться на нескольких уровнях:

  1. На этапе перетаскивания: через moves можно запретить начинать drag для элементов, которые не должны быть изменены.
  2. На этапе вставки: через accepts можно проверять типы контейнеров, допустимые позиции и свойства элемента.
  3. После вставки (drop событие): можно проводить дополнительную проверку данных и при необходимости откатывать перемещение.

Пример комплексной проверки:

dragula([todoList, completedList], {
    moves: function(el, source) {
        return !el.classList.contains('locked');
    },
    accepts: function(el, target) {
        if (target.id === 'completed' && el.dataset.priority === 'high') {
            return false; // нельзя перемещать элементы с высоким приоритетом
        }
        return true;
    }
}).on('drop', function(el, target, source, sibling) {
    if (target.id === 'completed' && el.dataset.dueDate < Date.now()) {
        source.insertBefore(el, sibling); // откат для просроченных задач
    }
});

Расширение Dragula для сложной валидации

Dragula предоставляет базовые инструменты, но их можно комбинировать с пользовательскими функциями валидации:

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

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

function validateDrop(el, target) {
    if (target.children.length >= 5) return false;
    if (el.dataset.type !== target.dataset.accept) return false;
    return true;
}

Затем интегрировать их в Dragula:

drake.on('drop', function(el, target, source, sibling) {
    if (!validateDrop(el, target)) {
        source.insertBefore(el, sibling);
    }
});

Особенности работы с динамическим DOM

При динамическом добавлении контейнеров или элементов важно повторно инициализировать Dragula или использовать делегированные события. Dragula автоматически не отслеживает новые DOM-узлы, поэтому новые контейнеры должны быть добавлены в массив containers через метод drake.containers.push(newContainer).

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

Использование Dragula в реальных приложениях

Dragula подходит для:

  • Панелей управления задачами (kanban-доски).
  • Сортируемых списков с различными типами элементов.
  • Сложных форм с drag-and-drop ввода данных.
  • Динамических таблиц, где порядок строк может меняться.

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