Привет, Хабр!
Как-то, год назад я писал о своей небольшой библиотеке, которая облегчает разработку форм на сайтах. Недавно я выпустил 3-ю версию, которая, по-сути, была переписана с нуля, чтобы стать правильней и удобней. Но в своей статье я не буду повторять README и ДЕМО, а лучше покажу на практике, каким образом она помогает писать меньше кода.
Но прежде, хотелось бы дать немного информации о новой версии. В ней, я избавился от зависимости malsup jquery.form для отправки файлов, и один большой репозитарий я разделил на несколько мелких самостоятельных репозитариев, сохранив, при этом, общую сборку "всё-в-одном":
- поддержка дополнительных событий форм (form-extra-events);
- полифил HTML5 form-атрибутов (form-association-polyfill);
- поддержка отправки файлов через iframe для старых браузеров (jquery-iframe-ajax);
- и, собственно, сама библиотека (paulzi-form).
Дополнительные события форм
Во второй версии библиотеки я столкнулся с проблемой необходимости соблюдения определённого порядка подключения скриптов. Например, раньше нельзя было подключать данный скрипт перед стандартным скриптом валидации Yii2, дело в том, что на событие submit навешиваются все скрипты, которые так или иначе должны обработать отправку, в частности произвести валидацию, и нет никакой гарантии что кто-то это событие не прервёт вызовом
preventDefault()
. Поэтому, в случае неверного порядка подключения, сначала происходила блокировка формы, а затем валидация, и, если были ошибки валидации, повторно отправить форму было уже нельзя. form-extra-events решает эту проблему, он предоставляет несколько новых типов событий формы, одно из которых гарантирует то, что форма отправляется, и этот процесс уже нельзя прервать. Кроме того, генерируются события начала и завершения отправки формы, что используется во всех остальных возможностях библиотеки.
Сайт-прототип

https://paulzi.ru/misc/github/paulzi-form/v3-site/
Из скриптов используем только jQuery, bootstrap и paulzi-form.all.js. В данном прототипе мы не используем ни строчки JS-кода написанного специально для сайта-прототипа.
Html5 form-атрибуты

switch($action)
, вместо того, чтобы сразу направить на конкретный action (например, в Yii2). А если вы откроете модальное окно, то увидите, что кнопку отправки пришлось сделать вне самой формы, тем не менее она продолжает функционировать, так как ей был указан атрибут form
. А самое главное, данные атрибуты сильно выручают в ситуациях, когда в большой форме нужно сделать маленькую форму, что стандарт HTML запрещает.
Не отправлять пустые поля

?proce_from=&proce_to=&tdp_from=&tdp_from=&line[]=i5
Используя библиотеку, если добавить к форме атрибут data-submit-empty="false"
незаполненные поля не будут отправляться, и в результате получится более человекопонятный URL:
?line[]=i5
Блокировка повторной отправки

data-lock="false"
Индикация состояния отправки

data-loading-text
и data-loading-icon
, которые изменяют текст кнопки и добавляют иконку. Также к форме и кнопке добавляются классы form-loading
и btn-loading
, это позволяет застилизовать состояние через CSS.
AJAX-отправка формы
Ну и самое главное, это возможность отправки формы через AJAX. Действительно, у нас в прототипе есть две формы в модальных окнах, логично при нажатии на кнопку отправки не осуществлять переходы между страницами, а просто закрыть модальное окно и вывести сообщение об успехе. И тут всё очень легко — добавляем атрибут
data-via="ajax"
, и вуаля, форма отправляется через AJAX. И мало того, те, кто хоть раз занимался передачей через AJAX файлов знает, что сделать это не так просто, т. к. поддержка отправки файлов появилось только начиная с XMLHttpRequrest 2. Для этого часто подключают сторонние библиотеки, которые часто требуют написания на серверной части особых обработчиков, хранить файлы во временной папке, а потом при отправке формы в отдельном запросе их оттуда забирать. В нашем же случае, об этом практически не надо задумываться — всё идёт также, как если бы форма отправлялась стандартным способом. При необходимости можно легко вывести процент отправленных данных, подцепившись на событие uploadprogress
.
Обработка AJAX-ответов

<span class="badge" data-insert-context="document" data-insert-to=".cart-block .badge" data-insert-mode="replaceWith">43</span>
<div class="alert alert-success alert-dismissible" role="alert" data-insert-context="document" data-insert-to=".alert-fixed">
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span></button>
Товар добавлен в корзину!
</div>
<div class="cart-block-hover" data-insert-context="document" data-insert-to=".cart-block-hover" data-insert-mode="replaceWith">
<div class="row">
<div class="col-xs-6 text-left">AMD K6</div>
<div class="col-xs-6">10 шт.</div>
</div>
<div class="row">
<div class="col-xs-6 text-left">Intel Celeron</div>
<div class="col-xs-6">12 шт.</div>
</div>
<div class="row">
<div class="col-xs-6 text-left">Intel Core i7</div>
<div class="col-xs-6">1 шт.</div>
</div>
<div class="row cart-block-total">
<div class="col-xs-6 text-left">Итого:</div>
<div class="col-xs-6"><span class="price"><span>117 000</span> ₽</span></div>
</div>
</div>
Как видите, ответ состоит из трёх html-элементов с атрибутами data-insert-to
, data-insert-context
, data-insert-mode
. Эти атрибуты определяют как и в какое место вставить каждый элемент, например, для первого span.badge
data-insert-context="document" data-insert-to=".cart-block .badge" data-insert-mode="replaceWith"
означает, что данным элементом нужно заменить элемент .cart-block .badge
и зона поиска данным селектором — весь документ. Всё это позволяет провести описанные выше действия без единой строчки кода.
Сценарии

data-via
атрибут, который укажет как отправлять форму при нажатии на неё.
Настройки
Если вам что-то не нравится, или возникают какие-либо конфликты, в библиотеке можно многое поменять через настройки. Например, нужно ли блокировать повторную отправку всех форм по-умолчанию. Все названия атрибутов также можно поменять.
Заключение
В итоге, подключив библиотеку размером 10 кб, вы получаете самое главное — нужно меньше писать код для разных мелких форм (а то и вовсе не писать), а в довесок получаете несколько приятных возможностей, такие как дополнительные события форм, iframe-транспорт, AJAX-отправка файлов и др.