AJAX MVC
- у нас есть HTML страничка, оформленная CSS
- вы куда ни будь кликаете
- JavaScript отправляет запрос на сервер (PHP скрипту)
- JavaScript обновляет содержимое HTML страницы
В действии (пример)
Чтобы оправдать концепцию мы рассмотрим небольшое приложение в качестве примера. Простая HTML страница с кнопкой, оформленная CSS. Она содержит два JavaScript’a отвечающих за события (Контролер) и за обновления страницы (Вид). Также страница будет содержать два вспомогательных JavaScript’а, так как я использую YUI (Yahoo User Interface) библиотеку. JavaScript’овый Контролер будет связан с кнопкой, по нажатию этой кнопки он отправит запрос PHP Контролеру. PHP Контролер (просто switch) разбирает запрос и вызывает соответствующий объект бизнес модели. В нашем случае «объект модели» это простая функция, но вы легко можете ее расширить. Модель возвращает (в JSON формате) ответ, в нашем случае это список установленных расширений PHP. Теперь используя полученные данные, JavaScript Вида обновляет содержимое страницы. Затем Вид вызывает другую функцию из JavaScript’ого Контролера, которая добавляет новые обработчики событий для нового контента. (Оп, тут небольшая ошибочка, было бы лучше, если бы ответы Модели отлавливались JavaScript’овым контролером, который бы активировал обработчики обновления JavaScript’ового вида, в любом случае это легко исправить)
Структура каталогов:
Код для примера
Мы добрались до самого интересного – реализации. Начнем с простого .html страницы, главной части вида.
Index.html:
< ?xml version=”1.1″ encoding=”iso-8859-1″?>
< !DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>
Welcome
Welcome to my app!
Это фрагмент из behaviours.js:
// класс событий
var behaviours = {
phpcontroller: "../controller/switch.php?request=",
// продолжаются behaviour.methods ….
}
// загрузка страницы, добавляем onload событие
YAHOO.util.Event.addListener(
'thebutton', 'click', behaviours.theButtonClick);
Теперь, когда пользователь кликнет по кнопке, вызовется метод behaviours.theButtonClick(), что в свою очередь отправит запрос PHP контролеру и сообщит ему тип запроса: "loadSomething":
theButtonClick: function(e) {
alert('Ouch! nnOK, I'll make a request for ya, buddy!');
YAHOO.util.Connect.asyncRequest (
'GET',
behaviours.phpcontroller + 'loadSomething',
{success: updates.writeContent}
);
},
PHP контроллер (controller/switch.php) получит запрос, пройдет switch (проверит тип запроса) и вызовет соответствующую (в нашем случае простую) функцию из бизнес модели. Полный код switch.php:
< ?php
// если это запрос
if (empty($_GET[’request’])) {
die();
}
// получить бизнес-логику
include_once ‘../model/business.php’;
// разбор запроса
// и вызов объекта логики
switch ($_GET[’request’])
{
case ‘loadSomething’:
echo loadSomething();
break;
case ‘loadSomeMore’: // не используется, только для примера
echo loadSomeMore();
break;
}
?>
Функция loadSomething() из PHP модели получает список установленных PHP расширений, кодируем в JSON и отправляем назад. Полный листинг ../model/business.php:
< ?php
function loadSomething() {
$extensions = get_loaded_extensions();
return ‘[”‘. implode(’”,”‘, $extensions) . ‘”]’;
}
?>
Если вернуться назад и взглянуть на AJAX запрос, можно увидеть, что в случае успеха, я вызываю метод updates.writeContent(). В ../view/updates.js содержится код обновления исходной html страницы, который создает HTML таблицу с результатами (списком расширений PHP). Потом я хотел прикрепить листенер к новой таблице, но это уже работа JavaScript’ового Контролера. Полный листинг updates.js:
var updates = {
writeContent: function (xmlhttp) {
if (!xmlhttp.responseText) {
alert("I got nothing from the server");
}
var data = eval(xmlhttp.responseText);
var write_to = document.getElementById('content');
write_to.innerHTML = '';
var html2dom_root = write_to;
var table = document.createElement("table");
var table_1_tbody = document.createElement("tbody");
for (var i in data) {
table_1_tbody_2_tr = document.createElement("tr");
table_1_tbody_2_tr_1_td = document.createElement("td");
num = 1 + parseInt(i);
table_1_tbody_2_tr_1_td_1_text = document.createTextNode(num);
table_1_tbody_2_tr_1_td.appendChild(table_1_tbody_2_tr_1_td_1_text);
table_1_tbody_2_tr.appendChild(table_1_tbody_2_tr_1_td);
table_1_tbody_2_tr_2_td = document.createElement("td");
table_1_tbody_2_tr_2_td_1_text = document.createTextNode(data[i]);
table_1_tbody_2_tr_2_td.appendChild(table_1_tbody_2_tr_2_td_1_text);
table_1_tbody_2_tr.appendChild(table_1_tbody_2_tr_2_td);
table_1_tbody.appendChild(table_1_tbody_2_tr);
}
table.appendChild(table_1_tbody);
html2dom_root.appendChild(table);
behaviours.updateTableBehaviour();
}
}
(Кстати, чтобы облегчить себе жизнь, при работе с DOM, я использовал свою небольшую утилиту )
И, наконец, оставшаяся часть JavaScript’ового Контролера (behaviours.js): метод behaviours.updateTableBehaviour(), который добавляет листенер к новой таблице и метод trClick(), который отлавливает клики по этой таблице. По клику просто меняется цвет выбранной строки.
trClick: function (e) {
var target = (e.srcElement) ?
e.srcElement.parentNode : e.target.parentNode;
if (target.tagName == 'TR') {
if (target.className == 'tr-on') {
target.className = '';
} else {
target.className = 'tr-on';
}
}
},
updateTableBehaviour: function () {
var el = document.getElementById('content').firstChild;
YAHOO.util.Event.addListener(
el, 'click', behaviours.trClick);
}
Демо и исходники
• – on-line демонстрация
• – весь исходный код этого примера
• – исходный код примера, но часть кода закомментирована, так что вы можете использовать его в качестве шаблона для ваших будущий AJAX проектов. Единственное, что нужно сделать - кинуть в папку _extras/yui.
Еще об этом:
Помоему, представление вида в DOM — изврат. Лучше использовать XSLT.
Zdrastvui Boris, bolshoe spasibo!
Solid, XSLT can often be a pain to start with, the learning curve is a bit sharp, but you’re free to use it with this little framework, won’t be a problem. It’s true that the DOM-way can be a bit verbose, but on the other hand it’s quite easy to understand. And in this case I used this sort of code-gen utility to produce it, so maybe the variable names could have been better than the “izvrat” as you put it
> С Моделью все просто, это бизнес логика
Модель – содержание системы
Вид – представление
Контроллер – содержит код бизнес логики
Беру свои слова обратно.
Просто в одной книге было написано, что: “Контроллер – содержит код бизнес логики”. Почитал статьи в инете, в которых везде пишут, что модель – бизнес логика.
И ничего не осталось, как поменять мнение.