Валидатор html форм
Всем привет. В этой статье я хочу выложить свеже-написанный скрипт валидации форм и объяснить, как с ним работать. Данный скрипт позволяет валидировать данные, введенные пользователем в html - форму страницы перед отправкой их на сервер, предоставляя для этого удобный и расширяемый функционал. Что в нём особенного?
- Он представляет собой единый модуль и не засоряет собой пространство имен.
- Прост в интеграции.
- Работает во всех основных браузерах, включая линейку IE от 6-ой до 9-ой версии
- НЕ использует JQuery
- НЕ нарушает web стандарты
- Мало вЕсит
- Указывает ошибки валидации рядом с полем ввода.
- Имеет возможность расширения/индивидуальной настройки.
- Настраиваемая мультиязычность
Мечта ... блин! 
Обновлено 14-05-2012 Листинг ниже остался прежним, все изменения и пример смотрим в архиве.
- Исправлена ошибка, когда в форме применяются fieldset-ы
- Теперь скрипт умеет проверять значения указанных полей на идентичность(когда требуется подтверждение пароля например)
Архив с обновленным скриптом и примером можно скачать тут
Вот рабочий пример:
В начале сделаю небольшое пояснение. Скрипт позволяет проверять значения текстовых полей типа INPUT и TEXTAREA. На сколько я могу судить об остальных элементах форм, то они, как раз разработаны таким образом, что пользователь может выбрать или установить только заранее определённые значения. Это элементы типа SELECT, CHECKBOX, RADIOBUTTON и т.д. - значения этих элементов, как правило задаются разработчиками, и по моему скромному мнению не нуждаются в валидации, по крайней мере, если использовать их правильно.
Конечно другие JQ - монстры с подобным предназначнием позволяют валидировать хоть чёрта лысого, в том числе и радиокнопки, но по-моему это уже перебор. Вес у тех товарищей конечно соответственный + конечно необходимость наличия самой JQ. Плагин JQ validate несомненно более продвинутый, и более сложен чем мой, НО и размер у него больше.
Ниже я привёл листинг объекта валидатора.
Валидатор html форм:
/**
* Объект "validator"
*/
var validator = (function( GLOB ){
return {
// Объект для тестов. Здесь он пустой
// Наполняется он в файле validator_tests.js
tests : {},
/**
* Метод для валидации формы.
* Вешается на обработчик onsubmit
* @param object form: Объект html формы.
* @return boolean true|false
*/
check : function ( form ) {
var DOC = GLOB.document, // Зависимость
elements = form.elements, // Здесь будут элементы формы
elLength = elements.length, // Количество элементы формы
require = false, // Флаг: обязательно ли поле
curItem = null, // Текущий (для цикла) элемент формы
curVal = null, // Текущее (для цикла) значение элемента формы
curTest = null, // Текущий (для цикла) класс/тест элемента формы
errSpan = null, // Контейнер для ошибок элемента формы
tests = [], // Здесь будут классы/тесты элемента формы
errors = {}, // Флаг указывает есть ли ошибки
prop = null, // Своство для обхода объекта errors
testsLength = 0, // Количество классов/тестов элемента формы
i, // Счётчики циклов
q;
for (i = 0; i < elLength; i += 1) {
// Получаем текущий элемент:
curItem = elements[i];
// Получаем текущее значение:
curVal = curItem.value;
// Пропускаем элементы не имеющие классов/тестов:
if (typeof (curItem.className) === "undefined") {
continue;
}
// Узнаём обязателен ли текущий элемент:
require = (curItem.className.indexOf("require") !== -1);
// Пытаемся получить ссылку на элемент-контейнер ошибок:
errSpan = DOC.getElementById(curItem.name + "_error");
// Если элемента-контейнера не существует
if (!errSpan) {
// ... формируем его:
errSpan = DOC.createElement("SPAN");
errSpan.id = curItem.name + "_error";
errSpan.className = "error";
// и добавляем его в DOM - древо,
// сразу после текущего элемента формы.
curItem.parentNode.insertBefore(errSpan, curItem.nextSibling);
}
// Если текущий элемент не обязателен и не заполнен...
if (curVal.length < 1 && !require) {
// Очищаем его контейнер, на случай, если он уже содержал текст ошибки,
errSpan.innerHTML = "";
// и пропускаем итерацию цикла.
continue;
}
// Получаем имена классов/тестов в массив:
tests = curItem.className.split(" ");
// Получаем длину массива:
testsLength = tests.length;
// Проходим по массиву классов/тестов циклом:
for (q = 0; q < testsLength; q += 1) {
// Получаем текущее имя класса:
curTest = tests[q];
// Если текущее имя класса не является тестом...
if (!this.tests.hasOwnProperty(curTest)) {
// пропускаем итерацию.
continue;
}
// Собсна проверка:
if (!curVal.match(this.tests[curTest].condition)) {
// Устанавливаем флаг для этой ошибки:
errors[curItem.name] = true;
// Не удачно - пишем ошибку в контейнер:
errSpan.innerHTML = this.tests[curTest].failText;
// Останавливаем цикл - вывод остальных ошибок для этого элемента не нужен,
// - не зачем пугать пользователя, пусть сначала устранят ту ошибку что есть.
break;
} else {
// Снимаем флаг ошибки:
errors[curItem.name] = false;
// Удачно - очищаем контейнер от содержимого.
errSpan.innerHTML = "";
} // END IF
} // END FOR
} // END FOR
/*
* Проверяем наличие установленных флагов ошибок.
* Если ошибок нет возвращаем true - в этом случае
* Обработчик "onsubmit" должен штатно отработать.
*/
for( prop in errors ) {
if ( errors.hasOwnProperty(prop) && errors[prop] === true) {
return false;
}
}
return true;
}
};
}(this));
Как всегда я старался писать как можно проще и меньше - если убрать комментарии то он занимает 62 строчки... меньше не получилось
И так, вы можете скачать архив и покопаться там самостоятельно, а можете почитать статью здесь я подробно объясню, что да как. Вобщем давайте попробуем поработать с моим валидатором.
По-сути сам объект "validator" состоит из двух вещей - это внутренний объект: tests, который содержит внутри себя тесты, и собственно сам метод валидации: check, который принимает ссылку на объект html формы и возвращает TRUE или FALSE в зависимости от результата валидации.
Для начала создадим html форму, такого вида (я постарался задействовать все реализованные тесты):
<fieldset>
<legend>Пример формы</legend>
<form id="myform" action="#" method="post" name="myform">
<div>
<label for="login">Обяз., англ. буквы и пробелы:</label>
<input id="login" type="text" name="login" class="require_ws en_char something somewhere" />
</div>
<div>
<label for="first_name">Обяз., рус. букы и пробелы:</label>
<input id="first_name" type="text" name="first_name" class="require ru_char something somewhere" />
</div>
<div>
<label for="last_name">Не обяз., рус. букы и пробелы:</label>
<input id="last_name" type="text" name="last_name" class="ru_char" />
</div>
<div>
<label for="mynumeric">Не обяз., целые и веществ. числа:</label>
<input id="mynumeric" type="text" name="mynumeric" class="numeric" />
</div>
<div>
<label for="myinteger">Обяз., целые числа:</label>
<input id="myinteger" type="text" name="myinteger" class="require integer" />
</div>
<div>
<label for="mycred_card">Обяз., кредит. карта:</label>
<input id="mycred_card" type="text" name="mycred_card" class="require cred_card" />
</div>
<div>
<label for="email_addr">Обяз., email адрес</label>
<input id="email_addr" type="text" name="email_addr" class="require email" />
</div>
<div>
<label for="myipv4">Обяз., IPv4 адрес</label>
<input id="myipv4" type="text" name="myipv4" class="require ipv4" />
</div>
<div>
<label for="mydomain">Обяз., доменное имя</label>
<input id="mydomain" type="text" name="mydomain" class="require domain" />
</div>
<div>
<label for="notice">Обяз., рус, без спец. символов</label>
<textarea id="notice" name="notice" class="require_ws ru_char no_special_chars" ></textarea>
</div>
<div class="centered">
<button name="send_form" type="submit">Отправить</button>
</div>
</form>
В названиях классов для элементов INPUT и TEXTAREA размещаются названия нужных нам тестов, пройдя которые, поле считается корректно заполненным. Присмотритесь к примеру ниже:
...
<input id="first_name" type="text" name="first_name" class="require ru_char something somewhere" />
...
<input id="last_name" type="text" name="last_name" class="ru_char" />
...
<input id="phone" type="text" name="phone" class="digits" />
...
<input id="email_addr" type="text" name="email_addr" class="require email" />
...
<textarea id="notice" name="notice" class="require en_char no_special_chars" ></textarea>
...
Эти самые тесты на все случаи жизни написать не возможно, поэтому я сделал возможность для пользователей писать эти тесты самостоятельно, под собственные нужды. Конечно несколько распространенных тестов я всё же написал за вас, но и их вы можете переопределить. Я специально вынес их в отдельный файл: validator_tests.js который нужно подключить после основного: validator.js (или сжатая версия: validator.pack.js) Там же, в файле validator_tests.js - тексты ошибок можно переписать на любом языке - вот Вам ещё и мультиязычность
Тест, как таковой, представляет собой простую конструкцию - это объект содержащий всего два свойства, я назвал их соответственно failText - "текст ошибки" и condition - "условие". Ниже приведён код тестов для русских и английских букв из файла validator_tests.js:
/**
* Проверка ввода русских букв и пробелов:
*/
validator.tests.ru_char = {
failText : "Допустимы только русские буквы и пробелы.",
condition : /^[а-яё\s]+$/i
};
/**
* Проверка ввода латинских букв и пробелов:
*/
validator.tests.en_char = {
failText : "Допустимы только английские буквы и пробелы.",
condition : /^[a-z\s]+$/i
};
"Текст ошибки" - это строка, которую увидят пользователи, если значение в поле ввода не пройдёт валидацию, а "условие" - это регулярное выражение, которому должно соответствовать значение в поле ввода. Конечно, для того, чтобы писать под себя тесты, вы должны уметь составлять регулярные выражения, или у вас должен быть друг.., который умеет составлять регулярные выражения
Для того, что бы Вы понимали, под что вам нужно будет писать регулярки - приведу кусок псевдо-кода, где происходит проверка (оригинал кода это строка 74 в листинге валидатора):
if (!проверяемое_значение.match(this.tests[текущий_тест])) {
// проверка НЕ пройдена ...
} else {
// проверка пройдена ...
}
Видите результат работы метода match инвертируется? Принцип такой: если в значении подопытного поля не найдено, ничего, что противоречит шаблону, то это значение пройдёт проверку.
- ru_char - Допустимы только русские буквы и пробелы.
- en_char - Допустимы только английские буквы и пробелы.
- integer - Проверка ввода целых чисел.
- numeric - Проверка ввода целых, вещественных, положительных и отрицательных чисел.
- email - Проверка ввода email*
- require - Обязательное поле.
- require_ws - Обязательное поле без учёта пробелов.
- ipv4 - проверка ввода IPv4-адреса*
- domain - проверка ввода доменного имени*
- cred_card - Все основные кредитные карты*
В скрипте УЖЕ реализованы следующие тесты, вам нужно просто подставить их в атрибут class="" нужного поля :
* - Эти вещи частично или полностью заимствованы из библиотеки программы RegexBuddy( Не на правах рекламы - прикольная прога).
Далее подключаем файл скрипта - валидатора и тестов
<script type="text/javascript" src="validator.js"></script>
<script type="text/javascript" src="validator_tests.js"></script>
и для примера определим ещё один, пользовательский тест - no_special_chars, он уже прописан для элемента TEXTAREA в html форме, но не существует в базовом варианте скрипта.
Допустим этот тест НЕ должен пропустить следующие символы: /?:@&=+$# ( тем более, что их не сможет закодировать encodeURI(), хотя их прекрасно кодирует encodeURIComponent() ).
Все пользовательские тесты должны стать свойствами объекта validator.tests, и должны реализоваться следующим образом :
<script type="text/javascript">
// Определяем собственный тест:
validator.tests.no_special_chars = {
failText : "Специальные символы не допустимы!",
condition : /^[^\/?:@&=+$#]+$/im
};
Теперь подключим наш валидатор к форме:
// Вешаем обработчик на событие отправки формы:
document.myform.onsubmit = function(){
return validator.check(this);
}
</script>
Ну, вот по сути и всё! Надеюсь понятно объяснил. Пример вы видели в самом начале. - Пользуйтесь на здоровье :)
Информация копипастерам
Внимание! Копирование контента с сайта, возможно только с разрешения администратора. Т.е. Меня! Я скорее всего разрешу Вам это сделать, в обмен на живую ссылку, на статью оригинал.
Валидатор html форм
