Текст ниже — перевод статьи "Unobtrusive Javascript", чей автор Christian Heilmann любезно дал мне согласие на перевод. Оригинальный адрес статьи www.onlinetools.org/articles/unobtrusivejavascript/chapter5.html.
Улучшать формы с помощью JavaScript — это очень хорошая идея. Ничто не расстраивает больше, чем заполнить форму, отправить ее серверу, ожидать пока страница загрузится и получить уведомления, что вы забыли заполнить то или другое поле.
Для пользователя куда приятнее получить ответ немедленно, еще до отправки данных, нам же это уменьшит серверный трафик.
JavaScript может сделать форму гораздо лучше, увеличив ее юзабилити, но мы должны осознавать несколько вещей:
<input class="required"/>
, но они не отсылаются при отправлении формы.<form action="formsend.php" method="post" onsubmit="return checkform(this);"> <p> <input type="hidden" name="required" id="required" value="name,surname,email,tac,msg,contactform" /> <label for="name">Name</label> <input type="text" name="name" id="name" /><span>*</span> </p> <p> <label for="surname">Surname</label> <input type="text" name="surname" id="surname" /><span>*</span> </p> <p> <label for="email">Email</label> <input type="text" name="email" id="email" /><span>*</span> </p> <p> <label for="phone">Phone number</label> <input type="text" name="phone" id="phone" /> </p> <p> <label for="contactform">Prefered form of contact</label> <select id="contactform" name="contactform"> <option value="">Please choose</option> <option value="p">phone</option> <option value="e">email</option> </select><span>*</span> </p> <p> <label for="msg">Your message</label> <textarea name="msg" id="msg"></textarea><span>*</span> </p> <p> <input type="checkbox" name="tac" id="tac" /> I have read the <label for="tac">terms and conditions</label> and agree with them.</label><span>*</span> </p> <p> <input type="submit" value="Send information" /> </p> </form>
Это отлично сверстанная форма, выполненная с метками, чтобы приспособить ее для не пользующихся мышью (non-visual) пользователей и тем пользователей, которым может быть трудно попасть в чекбокс их координатно-указательным устройством(мышью, трэкболом и т.д.). Для валидации, у нас есть скрытое поле называемое required
(обязательные), оно содержит список всех обязательных для заполнения полей через запятую. Это стандарт для скриптов валидации формы (помните formmail.pl
?) с незапамятных времен.
Правила, которым мы хотим следовать:
Большинство скриптов для валидации выводят список неправильно заполненных обязательных полей в предупреждение (alert
) JavaScript. В этом есть смысл, если форма велика и сложна, но предупреждения раздражают и несколько отталкивают. Давайте попробуем для этой небольшой формы другой подход: каждое поле, в котором есть ошибка, должно получить небольшую иконку с предостерегающим знаком и красный цвет фона, а также мы покажем сообщение над кнопкой отправки формы (submit button), в котором говорится, что найдены ошибки.
Мы начинаем наш скрипт с тестирования, доступна ли DOM, и существует ли поле с ID required
. Если не выполняется хотя бы одно из этих условий, мы возвращаемся к документу, и наш покой будет обеспечивать теперь PHP-скрипт обработки ошибок formsend.php
.
function checkform(of) { if(!document.getElementById || !document.createTextNode){return;} if(!document.getElementById('required')){return;}
Продолжаем, определяя все переменные, используемые в отображении ошибки, и разбивая строку — список ID обязательых полей в поле required
— в массив.
var errorID='errormsg'; var errorClass='error' var errorMsg='Please enter or change the fields marked with a '; var errorImg='img/alert.gif'; var errorAlt='Error'; var errorTitle='This field has an error!'; var reqfields=document.getElementById('required').value.split(',');
Раз мы добавляем элемент с определенным ID в errorID, а также изображения к каждому неправильно заполненному полю, нам нужно удалить все это, когда скрипт будет выполняться во второй раз. Иначе у нас будет несколько сообщений об ошибке и несколько изображений.
// Удаляем старые сообщения // если есть старое поле errormessage, удаляем его if(document.getElementById(errorID)) { var em=document.getElementById(errorID); em.parentNode.removeChild(em); } // удаляем старые изображение и классы // в обязательных для заполнения полях for(var i=0;i<reqfields.length;i++) { var f=document.getElementById(reqfields[i]); if(!f){continue;} if(f.previousSibling && /img/i.test(f.previousSibling.nodeName)) { f.parentNode.removeChild(f.previousSibling); } f.className=''; }
Сейчас мы сделаем то, что потом уберем к прежнему состоянию. Мы перебираем обязательные поля и проверяем, в первую очередь, существует ли поле. Если нет, мы пропускаем один круг цикла. Это делается исключительно, чтобы избежать сообщений об ошибках, в настоящей же форме должны быть все обязательные поля.
// перебираем обязательыне поля for(var i=0;i<reqfields.length;i++) { // проверяем, существует ли это обязательное поле var f=document.getElementById(reqfields[i]); if(!f){continue;}
Потом мы проверяем каждое поле в соответствии с его типом. Для текстовых областей и полей мы должны проверить значение, для чекбоксов — отмеченный атрибут, для выпадающих меню — определен ли selectedIndex, и больше ли он 0.
Если в каком-то из полей есть ошибка, мы посылаем ее как объект методу cf_adderr()
. Особый случай — это поле email, так как оно также нуждается в проверке на правильность электронного почтового адреса. Эта проверка исполняется другим методом, называемым cf_isEmailAddr()
, в котором используются регулярные выражения.
// проверяем правильность заполнения обязательных полей // в соответствии с их типом switch(f.type.toLowerCase()) { case 'text': if(f.value=='' && f.id!='email'){cf_adderr(f)} // email — особое поле и требует иной проверки if(f.id=='email' && !cf_isEmailAddr(f.value)){cf_adderr(f)} break; case 'textarea': if(f.value==''){cf_adderr(f)} break; case 'checkbox': if(!f.checked){cf_adderr(f)} break; case 'select-one': if(!f.selectedIndex && f.selectedIndex==0){cf_adderr(f)} break; } }
Если какая-либо из проверок выше запускает отчет об ошибке, cf_adderr() создает сообщение об ошибке (DIV с errorId в качестве ID). Поэтому мы возвращаемся к процессу отправки формы, только когда этого элемента не существует.
return !document.getElementById(errorID);
Это главная функция, на данный момент нам нужно сконцентрироваться на используемых методах, первый это добавление изображений со знаками ошибки и сообщений об ошибках.