В этой статье разберем один из вариантов модели построения обработчиков элементов веб-интерфейсов на примере HTML-форм. Для понимания материала, изложенного в этой статье, от Вас потребуется знание объектной модели JavaScript.
Обычно встречаются 2 ситуации неправильно организованного алгоритма обработки веб-форм:
- Избыточное число слоёв и связей может усложнить небольшую форму. Само использование MVC не является ошибкой и не доказывает низкую производительность.
- Начинающие программисты пишут для каждой формы отдельный набор функций, и что хуже всего, хранят их в глобальном пространстве имен.
Если со второй ситуацией все ясно, со временем, такие программисты могут начать писать более грамотный код, то на первом случае остановимся поподробнее.
Для небольшой формы часть состояния удобно держать рядом с представлением. Это не универсальный запрет MVC: границы компонентов выбирают по сложности и требованиям приложения.
Для небольшой формы часть состояния удобно держать рядом с представлением. Это не универсальный запрет MVC: границы компонентов выбирают по сложности и требованиям приложения. Особенности Javascript/DOM/CSS позволяют успешно реализовывать аспекты Model средствами View
javascript.ru
Ниже рассматривается небольшой самостоятельный обработчик. Его можно встроить в более крупную архитектуру, сохранив общий контракт состояний и обратных вызовов.
Обработка форм
Итак, в начале статьи говорилось, что мы будем рассматривать модель обработчика элемента веб-интерфейса на примере HTML-форм.
Представим, что у нас в проекте будет несколько форм, которые будут совершенно одинаково оформлены. То есть способ отображение ошибок, сообщение об успешной отправке данных и т. д. будут отображаться во всех формах по единому принципу. Данные будут передаваться через AJAX. Если Вы уже сталкивались с написанием обработчиков форм, то наверное убедились, что один универсальный код для всех форм на все случаи написать невозможно, да это и не нужно. Такой обработчик для каждого проекта должен быть свой. А вот в рамках одного проекта все же можно и нужно выделить общий обработчик из конкретного функционала каждой формы.
Далее, чтобы немного сократить код, будет использоваться функция:
function $(id) {
return document.getElementById(id);
}Всего лишь сокращаем запись получения ссылки на DOM-узел по идентификатору. Эта функция обычно уже есть в Вашем наборе частоиспользуемых методов или входит в состав используемого в проекте фреймворка.
Воспользуемся функцией-конструктором, для создания объекта — обработчика формы:
function Form(id) {
this.form = $(id);
}Функция «Form» создает объект, с атрибутом «form», содержащим ссылку на HTML-форму, полученную по идентификатору. Для чего функция, если можно сразу записать объект, спросите Вы? Для того, чтобы было возможно использовать «prototype».
Добавим в «prototype» функции «Form» набор методов, которые будут использоваться в каждой форме нашего проекта:
Form.prototype = {
// функция init принимает 3 входных параметра;
// submit - функция, срабатывющая по событию формы onsubmit;
// success - функция вызываемая в результате
// успешной обработки формы;
// error - функция вызываемая при ошибке.
init: function(submit, success, error) {
// добавляем принятые функции, как методы текущего объекта
this.submit = submit;
this.success = success;
this.error = error;
// создаем атрибут, отвечающий за состояние формы
this.enabled = true; // включена
// создаем функцию, которая будет вызвана
// по событию формы onsubmit
var _this = this, listener = function(event) {
// Отменяем стандартную отправку до пользовательского кода:
// даже если process выбросит ошибку, native submit не запустится.
var ev = event || window.event;
ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
_this.process();
};
// добавляем созданный выше обработчик listener
// к событию формы onsubmit
// для нормальных браузеров
if(this.form.addEventListener)
this.form.addEventListener('submit', listener, false);
// для IE
//@cc_on this.form.attachEvent('onsubmit', listener);
},
// функция process выполняет дополнительные действия
// при вызове указанной пользователем функции submit
process: function() {
if(this.enabled) { // если форма включена
this.enabled = false; // отключаем форму
this.submit(); // вызываем функцию submit
}
},
// функция message управляет отображением сообщений
// об ошибках и удачной отправке данных
message: function(text) {
// здесь должен находиться код, отвечающий
// за способ отображения сообщений форм
// конкретного проекта
alert(text);
}
};Таким образом, мы создали конструктор объекта — обработчик формы, в списке методов которого есть 3 функции:
- «init» — функция, с которой будет начинаться работа с каждой формой. Она расширяет каждый новый объект, функциями, указанными программистом. Создает атрибут «enabled», отвечающий за состояние формы (влючена/выключена), для предотвращения повторной отправки данных, а так же отключает стандартное поведение формы по событию «
onsubmit». - «process» — выполняет дополнительные операции, присущие всем формам конкретного проекта, перед запуском указанной программистом функции «
submit». - «message» — управляет отображением информации об ошибках и успешной отправке. Должна быть тесно связана с версткой и оформлением форм в рамках конкретного проекта.
Как же теперь все это использовать? Да очень просто, а главное удобно:
// создаем новую копию объекта Form
// для HTML-формы с идентификатором "my-form"
var myForm = new Form('my-form');
// вызываем метод init и передаем ему 3 функции
myForm.init(
// submit
function() {
// здесь должен находится код, отвечающий
// за обработку конкретной формы, например,
// здесь мы проверяем, не пусты ли поля ввода
// с идентифкаторами "log" и "pwd"?
$('log').value && $('pwd').value ? this.success() : this.error();
},
// success
function() {
// показываем пользователю сообщение об
// успешной локальной проверке полей
this.message('Поля заполнены. Данные ещё не отправлялись.');
this.enabled = true;
},
// error
function() {
// показываем сообщение об ошибке
this.message('Ошибка');
// включаем форму для того,
// чтобы пользователь имел возможность
// повторить попытку снова
this.enabled = true;
}
);В показанном примере submit только проверяет, заполнены ли два поля, и ничего не отправляет по сети. Это демонстрация общих обработчиков и обратных вызовов. Для реального запроса добавьте отдельную серверную операцию, проверку ответа и восстановление состояния формы при ошибке; клиентская проверка не заменяет серверную.
В некоторых проектах функции «success» и «error» можно разместить в «prototype» функции-конструктора «Form», если способ отображения сообщений совершенно ничем не будет отличаться во всех формах проекта.
Чтобы добавить что-то еще, не предусмотренное функционалом метода «init», но необходимое для работы конкретной формы, можно использовать созданную ссылку на новую копию объекта «Form», например:
myForm.form.getElementsByTagName('input')[0].onfocus = function() {
// какой-то код…
};Вывод
Таким образом, мы создали обработчик HTML-форм в рамках одного конкретного проекта. Самым главным достоинством такого подхода является то, что написав подобный обработчик, при создании каждой новой формы Вам не придется задумываться о коде, отвечающем за ее оформление, которое в большинстве случаем в рамках одного проекта для всех форм одинаковое.
Этот же принцип можно применять и для других элементов веб-интерфейса.
Полезно почитать
Отвлекитесь от программирования и уделите внимание оформлению форм. Советую прочесть статью «Кроссбраузерное выравнивание кнопок-изображений в формах», сэкономите себе много времени в итоге.