- PVSM.RU - https://www.pvsm.ru -
Привет!
Как-то, год назад [1] я писал о своей небольшой библиотеке, которая облегчает разработку форм на сайтах. Недавно я выпустил 3-ю версию, которая, по-сути, была переписана с нуля, чтобы стать правильней и удобней. Но в своей статье я не буду повторять README [2] и ДЕМО [3], а лучше покажу на практике, каким образом она помогает писать меньше кода.
Но прежде, хотелось бы дать немного информации о новой версии. В ней, я избавился от зависимости malsup jquery.form [4] для отправки файлов, и один большой репозитарий я разделил на несколько мелких самостоятельных репозитариев, сохранив, при этом, общую сборку "всё-в-одном":
Во второй версии библиотеки я столкнулся с проблемой необходимости соблюдения определённого порядка подключения скриптов. Например, раньше нельзя было подключать данный скрипт перед стандартным скриптом валидации Yii2, дело в том, что на событие submit навешиваются все скрипты, которые так или иначе должны обработать отправку, в частности произвести валидацию, и нет никакой гарантии что кто-то это событие не прервёт вызовом preventDefault()
. Поэтому, в случае неверного порядка подключения, сначала происходила блокировка формы, а затем валидация, и, если были ошибки валидации, повторно отправить форму было уже нельзя. form-extra-events решает эту проблему, он предоставляет несколько новых типов событий формы, одно из которых гарантирует то, что форма отправляется, и этот процесс уже нельзя прервать. Кроме того, генерируются события начала и завершения отправки формы, что используется во всех остальных возможностях библиотеки.
Для демонстрации полезности библиотеки, я набросал прототип типичного интернет-магазина на Bootstrap:
http://paulzi.ru/paulzi-form-site/ [9]
Из скриптов используем только jQuery, bootstrap и paulzi-form.all.js. В данном прототипе мы не используем ни строчки JS-кода написанного специально для сайта-прототипа.
В чём может пригодиться HTML5 form-атрибуты? Например, в корзине [10] предполагается несколько действий над выбранными товарами — добавить в избранное, отправить на Email, скачать. Конечно, можно было бы сделать единый action, а в параметрах передавать, что конкретно нужно сделать. Но это некрасиво, т. к. порождает использование switch($action)
, вместо того, чтобы сразу направить на конкретный action (например, в Yii2). А если вы откроете модальное окно, то увидите, что кнопку отправки пришлось сделать вне самой формы, тем не менее она продолжает функционировать, так как ей был указан атрибут form
. А самое главное, данные атрибуты сильно выручают в ситуациях, когда в большой форме нужно сделать маленькую форму, что стандарт HTML запрещает.
Теперь, обратим внимание на фильтр в каталоге [9]. Если отметить галочкой «Intel Core i5» и отправить данную форму, то даже если другие поля не заполнены, мы всё равно получим длинную простыню из параметров после перехода:
?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. Действительно, у нас в прототипе есть две формы в модальных окнах, логично при нажатии на кнопку отправки не осуществлять переходы между страницами, а просто закрыть модальное окно и вывести сообщение об успехе. И тут всё очень легко — добавляем атрибут data-via="ajax"
, и вуаля, форма отправляется через AJAX. И мало того, те, кто хоть раз занимался передачей через AJAX файлов знает, что сделать это не так просто, т. к. поддержка отправки файлов появилось только начиная с XMLHttpRequrest 2. Для этого часто подключают сторонние библиотеки, которые часто требуют написания на серверной части особых обработчиков, хранить файлы во временной папке, а потом при отправке формы в отдельном запросе их оттуда забирать. В нашем же случае, об этом практически не надо задумываться — всё идёт также, как если бы форма отправлялась стандартным способом. При необходимости можно легко вывести процент отправленных данных, подцепившись на событие uploadprogress
.
Посмотрим на пример посложнее — кнопка добавления в корзину на странице каталога [9]. При нажатии на неё надо не просто выполнить запрос и вывести сообщение — нужно обновить краткий список содержимого корзины при наведении и обновить счётчик количества товаров в ней. Этот момент тоже учтён, и я постарался сделать максимально гибкий обработчик 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
и зона поиска данным селектором — весь документ. Всё это позволяет провести описанные выше действия без единой строчки кода.
Вернёмся на страницу корзины [10]. Как уже было рассмотрено выше, на неё есть несколько кнопок, которые подразумевают разные действия. Например, при нажатии на "оформить" логично отправить форму стандартным механизмом, после чего осуществить редирект на страницу с информацией о заказе. А вот при нажатии на "В избранное", наоборот, лучше не уходить со страницы, а просто отправить форму через AJAX и вывести сообщение об успехе или ошибке. Для этого реализованы сценарии — для любой кнопки можно указать data-via
атрибут, который укажет как отправлять форму при нажатии на неё.
Если вам что-то не нравится, или возникают какие-либо конфликты, в библиотеке можно многое поменять через настройки [11]. Например, нужно ли блокировать повторную отправку всех форм по-умолчанию. Все названия атрибутов также можно поменять.
В итоге, подключив библиотеку размером 10 кб, вы получаете самое главное — нужно меньше писать код для разных мелких форм (а то и вовсе не писать), а в довесок получаете несколько приятных возможностей, такие как дополнительные события форм, iframe-транспорт, AJAX-отправка файлов и др.
Перейти на страницу проекта в Github» [8]
Автор: PaulZi
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/161000
Ссылки в тексте:
[1] Как-то, год назад: https://habrahabr.ru/post/261347/
[2] README: https://github.com/paulzi/paulzi-form/blob/master/README.ru.md
[3] ДЕМО: http://paulzi.ru/paulzi-form/
[4] malsup jquery.form: http://malsup.com/jquery/form/
[5] form-extra-events: http://github.com/paulzi/form-extra-events
[6] form-association-polyfill: http://github.com/paulzi/form-association-polyfill
[7] jquery-iframe-ajax: http://github.com/paulzi/jquery-iframe-ajax
[8] paulzi-form: https://github.com/paulzi/paulzi-form
[9] http://paulzi.ru/paulzi-form-site/: http://paulzi.ru/paulzi-form-site/
[10] корзине: http://paulzi.ru/paulzi-form-site/cart.html
[11] настройки: https://github.com/paulzi/paulzi-form#global-options
[12] Источник: https://habrahabr.ru/post/306278/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.