Формы с динамическими полями

SortableJS — это легковесная библиотека на JavaScript, обеспечивающая возможность перетаскивания элементов внутри списка или между списками. Основная концепция заключается в том, что любой HTML-элемент, содержащий дочерние элементы, может быть превращен в “sortable”, то есть интерактивно перемещаемый список.

Инициализация SortableJS происходит через создание нового объекта Sortable:

const el = document.getElementById('items-list');
const sortable = new Sortable(el, {
    animation: 150,
    ghostClass: 'sortable-ghost',
    handle: '.drag-handle'
});
  • animation — скорость анимации при перемещении элемента в миллисекундах.
  • ghostClass — CSS-класс, применяемый к элементу, который перетаскивается, чтобы визуально отличать его от остальных.
  • handle — ограничивает область, за которую можно захватывать элемент для перетаскивания.

Перетаскивание между списками

SortableJS поддерживает связь нескольких списков. Это удобно для форм с динамическими полями, когда данные могут перемещаться между категориями:

const list1 = document.getElementById('list-1');
const list2 = document.getElementById('list-2');

Sortable.create(list1, {
    group: 'shared',
    animation: 150
});

Sortable.create(list2, {
    group: 'shared',
    animation: 150
});
  • group — объединяет списки в общую группу, позволяя перемещать элементы между ними.
  • Можно задавать объект вместо строки, чтобы более тонко управлять доступом для перетаскивания (pull, put).

События SortableJS

SortableJS предоставляет множество событий для тонкой настройки логики работы с элементами:

  • onStart — срабатывает при начале перетаскивания.
  • onEnd — вызывается при завершении перемещения элемента, позволяет обновить внутренние данные.
  • onAdd — срабатывает, когда элемент добавлен в список из другого списка.
  • onRemove — срабатывает при удалении элемента из текущего списка.
  • onUpdate — вызывается, когда элемент изменил своё положение внутри списка.

Пример обработки события onEnd для обновления порядка элементов в форме:

const formList = document.getElementById('form-fields');

Sortable.create(formList, {
    animation: 150,
    onEnd: function(evt) {
        const order = Array.from(formList.children).map(el => el.dataset.id);
        console.log('Новый порядок полей:', order);
    }
});

Динамическое добавление и удаление элементов

Для форм с динамическими полями важно, чтобы новые элементы автоматически становились перетаскиваемыми. Для этого можно использовать метод Sortable.create на вновь добавляемых элементах либо манипулировать DOM внутри уже существующего Sortable:

const addButton = document.getElementById('add-field');

addButton.addEventListener('click', () => {
    const newField = document.createElement('li');
    newField.textContent = 'Новое поле';
    newField.dataset.id = Date.now();
    formList.appendChild(newField);
});

SortableJS автоматически работает с новыми элементами, если они добавляются в контейнер после инициализации, так как отслеживает изменения DOM.

Настройка внешнего вида при перетаскивании

  • ghostClass позволяет применить прозрачность или границы к перетаскиваемому элементу.
  • chosenClass — класс для выбранного элемента до начала перемещения.
  • dragClass — класс для элемента во время перетаскивания.

Пример стилей:

.sortable-ghost {
    opacity: 0.4;
    border: 1px dashed #ccc;
}

.sortable-chosen {
    background-color: #f0f0f0;
}

.sortable-drag {
    transform: rotate(2deg);
}

Ограничение и сортировка

  • filter — позволяет запретить перетаскивание для определенных элементов.
  • disabled — временно отключает сортировку.
  • sort — включает или отключает возможность изменения порядка элементов внутри контейнера.

Пример:

Sortable.create(formList, {
    animation: 150,
    filter: '.no-drag',
    onFilter: function(evt) {
        console.log('Элемент заблокирован для перетаскивания:', evt.item);
    }
});

Работа с формами и данными

Для форм с динамическими полями ключевым аспектом является синхронизация порядка элементов с данными на сервере. При каждом перемещении можно создавать массив идентификаторов и отправлять его через AJAX:

onEnd: function(evt) {
    const data = Array.from(formList.children).map(el => el.dataset.id);
    fetch('/update-order', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ order: data })
    });
}

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