Валидатор html форм

Валидатор html форм

Всем привет. В этой статье я хочу выложить свеже-написанный скрипт валидации форм и объяснить, как с ним работать. Данный скрипт позволяет валидировать данные, введенные пользователем в html - форму страницы перед отправкой их на сервер, предоставляя для этого удобный и расширяемый функционал. Что в нём особенного?

  1. Он представляет собой единый модуль и не засоряет собой пространство имен.
  2. Прост в интеграции.
  3. Работает во всех основных браузерах, включая линейку IE от 6-ой до 9-ой версии
  4. НЕ использует JQuery
  5. НЕ нарушает web стандарты
  6. Мало вЕсит
  7. Указывает ошибки валидации рядом с полем ввода.
  8. Имеет возможность расширения/индивидуальной настройки.
  9. Настраиваемая мультиязычность

Мечта ... блин!

Обновлено 14-05-2012 Листинг ниже остался прежним, все изменения и пример смотрим в архиве.

  1. Исправлена ошибка, когда в форме применяются fieldset-ы
  2. Теперь скрипт умеет проверять значения указанных полей на идентичность(когда требуется подтверждение пароля например)

Архив с обновленным скриптом и примером можно скачать тут

Вот рабочий пример:

Пример формы

В начале сделаю небольшое пояснение. Скрипт позволяет проверять значения текстовых полей типа 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 инвертируется? Принцип такой: если в значении подопытного поля не найдено, ничего, что противоречит шаблону, то это значение пройдёт проверку.

    В скрипте УЖЕ реализованы следующие тесты, вам нужно просто подставить их в атрибут class="" нужного поля :

  • ru_char - Допустимы только русские буквы и пробелы.
  • en_char - Допустимы только английские буквы и пробелы.
  • integer - Проверка ввода целых чисел.
  • numeric - Проверка ввода целых, вещественных, положительных и отрицательных чисел.
  • email - Проверка ввода email*
  • require - Обязательное поле.
  • require_ws - Обязательное поле без учёта пробелов.
  • ipv4 - проверка ввода IPv4-адреса*
  • domain - проверка ввода доменного имени*
  • cred_card - Все основные кредитные карты*

* - Эти вещи частично или полностью заимствованы из библиотеки программы 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>
  

Ну, вот по сути и всё! Надеюсь понятно объяснил. Пример вы видели в самом начале. - Пользуйтесь на здоровье :)

Добавить комментарий


Защитный код
Обновить



Кто на сайте
Сейчас 35 гостей онлайн