FormValidator

22.01.2012 - 02:47
Авторы: V@s3K
Использованное ПО: PyCharm 2.0
URL: https://github.com/vas3k/FormValidator

Недавно мне понадобилась такая известная и, казалось бы, популярная вещь как клиентский валидатор форм. Да не простой валидатор, а интересный: форма у меня была многостраничная (заказ в магазине в несколько шагов, да еще и каждый зависит от выбора на предыдущем), плюс на одной из страниц была переключалка "физическое лицо" или "юридическое лицо", отображавшая ту или иную часть дополнительной формы. Это все тоже надо было как-то валидовать. Это еще не все - переход к каждому следующему шагу был возможен только при правильном заполнении всех полей текущего. В общем форма была одна и отсылалась как единое целое, но заполнялась по-частям. Вот такое веселье. Стало понятно, что без библиотеки клиентской валидации тут не обойтись и я пошел гуглить.

Первым делом я наткнулся на статью, в которой автор описывал свою библиотеку валидации. Почитав пару частей я понял, что по синтаксису и возможностям она меня полностью устраивает. Лицензия тоже подходила, да и исходники были вполне читаемые (насколько может быть читаем JavaScript, конечно), разобраться что делает каждая функция не составляло труда. Так, например, я обнаружил, что метод запуска валидации жестко привязывался к onsubmit, что сразу должно было мне показаться странным. Не беда, сделал вызов ручками, работает. Затем применил ее к первой странице - тоже работает, ко второй - на ней тоже работает. Решил вернуться к первой - хрен. Все сломалось. Чтобы долго не томить разговорами в итоге я прочитал код и понял, что валидатор вешает свои чеки прямо на dom-объекты input, а проверка идет просто циклом по всем (!) полям данной формы. Полез гуглить дальше, спрашивал в твиттере и других интернетах, в итоге все валидаторы либо жестко связаны с сервером, либо монструозны (кстати, рекомендую Яндексовский SVARX, если у вас большой проект), либо так же как наш подопытный привязываются к полям насильно. Даже если при этом они ходят только по тем полям, которые относятся лично к ним, они все равно запускают все валидаторы, приписанные к нему. Ну, был еще четвертый тип валидаторов - те, которые не подошли по другим причинам, так что не нужно забрасывать меня ссылками, уже поздно...

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

Основные возможности

1. Чисто клиентская валидация

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

Объект валидатор получает первым параметром id формы для валидации, вторым (необязательным) - набор правил. Второй скорее нужен для тех, кто формирует правила где-то еще, например, на сервере. Обычно хватает одного:

var validator = new FormValidator("my_form");

2. Множественная валидация одной формы

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

То есть подобный код вполне будет работать правильно:

var validator1 = new FormValidator("my_form");
var validator2 = new FormValidator("my_form");
...
validator1.validate();
validator2.validate();

Я решил не привязываться к onsubmit вообще, чтобы выполнить валидацию формы нужно вызвать метод .validate() руками, или привязаться к onsubmit самому. Явное лучше неявного, помните?

3. Множественная валидация одного поля

На одно поле можно навесить (и снять, кстати, тоже) несколько разных правил валидации по-отдельности. Просто подряд. Для меня было удивлением, что некоторые валидаторы это не умели или делали через такую жопу, что волосы на подмышках шевелились.

Создавать правила можно так:

validator.addValidation("username", "req", "Имя обязательно");
validator.addValidation("username", "min-len=5", "У вас слишком короткий... ник");
validator.addValidation("username", "max-len=20", "Слишком длинный");

Удалять так:

validator.removeValidation("username", "max-len");

Эта строчка удалит только требование максимальной длины, все остальные будут работать. Обратите внимание, что функция принимает названия полей, а не их id. Вся работа с полями только по аттрибуту "name".

4. Доступные из коробки валидаторы

Конечно, я не гнался особо за количеством валидаторов, добавил лишь самые необходимые и могу прикрываться тем, что каждый может создать свою функцию. Например, отсутствуют такие модные проверки как равенство двух полей (делается кастомно в 2 строки), что в поле только текст (делается через regexp-валидатор), что выбран один из радиобатонов (тоже кастомно), и.т.д. Как бы подразумевается, что вы можете сами написать функцию, которая будет возвращать true/false.

"req" - поле обязательно для заполнения

"int" - поле содержит целое число и ничего больше

"float" - поле содержит только вещественное число

"min-len" - текстовое содержимое поле длинее заданного значения (включительно)

"max-len" - то же, только короче (включительно)

"min-val" - поле содержит не только число, но еще и большее заданного (включительно)

"max-val" - то же, но наоборот

"email" - поле содержит email (проверка нестрогая, сделано специально)

"regexp" - валидация по регулярке (параметр передается на вход конструктору RegExp с модификаторами "ig")

Немного расскажу метод работы. При добавлении через addValidation() вы могли заметить, что некоторые названия имеют знак равенства. Такие названия автоматически парсятся на то, что до и то, что после. До - название валидатора, после - параметры, которые будут переданы в функцию. Итоговый элемент списка this.rules выглядит как:

{
"field_name": название поля (именно название, не id),
"check": кодовое название валидатора,
"param": параметр, который будет передан в функцию валидации,
"msg": строка ошибки
}

5. Создание собственных функций для валидации

Кому недостаточно встроенных валидаторов, можно создать свои. Функция должна возвращать true/false, а принимать два параметра field - dom-объект input'а, rule - тот самый, описанный ранее, элемент this.rules.

validator.addCustomValidator("my-validator", function(field, rule) { return true; });

Можно использовать его как с параметрами, так и без:

validator.addValidation("field_name", "my-validator=123", "Все плохо...");

6. Множество способов отобразить случившиеся ошибки

В том числе и определить свои. Для начала имеющиеся:

"alert" - отображает alert() на каждую ошибку (надеюсь, вы не совсем упороты, чтобы так делать, кроме как в целях дебага)

"color" - подсвечивает границы ошибочного поля (по умолчанию красным)

"color_label" - подсвечивает label поля (тоже красным, если не определено другое)

"flow" - создает новый блок с ошибкой динамически как dom-брата у input'а (по умолчанию имеет класс "flow_error")

"one" - отображает все ошибки в одном блоке (по умолчанию с id = error_block)

"block" - отображает ошибки в специальном блоке для каждого поля (id этого блока = <имя_поля>_errors)

"custom" - пользовательский тип

Подсвечивает лейблы

validator.addErrorHandler("color_label");

validator.addErrorHandler("color_label", "#00FF00");

Отображает все ошибки в одном блоке (во втором случае с id="errors")

validator.addErrorHandler("one");

validator.addErrorHandler("one", "errors");

Собственный метод отображения ошибки

validator.addErrorHandler("custom", function(field, rule) { alert(rule["msg"]); });

Пример

Конечно, все это можно посмотреть на github, упомянутом выше, но для интересующихся выложу и сюда:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Simple form validation demo</title>
</head>

<script src="../formvalidator.js"></script>

<script>
function onready() {
validator = new FormValidator("my_form");

validator.addErrorHandler("color_label"); // Highlight labels (red by default)
validator.addErrorHandler("one", "errors"); // Show errors in block <div id="errors">

// Username validation
validator.addValidation("username", "req", "Username required");
validator.addValidation("username", "min-len=5", "Username minimum length = 20");
validator.addValidation("username", "max-len=20", "Username maximum length = 20");

// Email validation
validator.addValidation("email", "req", "Email required");
validator.addValidation("email", "email", "This is SPAR^W not valid email");

// Text validation
validator.addValidation("text", "req", "Text required");
}
</script>

<body onload="onready();">
<div id="errors"></div>

<form action="#" method="post" id="my_form" onsubmit="return validator.validate(); // that's not so good, dude">
<p>
<label for="id_username">Name</label>
<input type="text" name="username" id="id_username" />
</p>

<p>
<label for="id_email">E-mail</label>
<input type="text" name="email" id="id_email" />
</p>

<p>
<label for="id_text">Text</label>
<textarea rows="2" cols="10" name="text" id="id_text"></textarea>
</p>

<p>
<input type="submit" />
</p>
</form>
</body>
</html>

Артур?! — 23.01.2012 - 00:47 [89.189.191.19] Windows
Да ты крут. Впрочем, когда не был-то, всё как обычно.
silka — 25.01.2012 - 11:41 [176.213.166.129] Windows
Спасибо Васе за это.
Vidog — 26.03.2012 - 02:26 [212.164.114.142] Windows
validator.addValidation("username", "min-len=5", "Username minimum length = 20");
validator.addValidation("username", "max-len=20", "Username maximum length = 20");

Копипасты - зло ;)
V@s3K — 26.03.2012 - 09:33 [178.49.15.6] Mac OS
Vidog, :3
refresh

i