Как написать AJAX-приложение
источник: Компьютерра
Это два года назад AJAX был в диковинку (да и самого слова AJAX тогда ещё не выдумали). Теперь веб-приложения, страницы которых обновляются "на лету", в порядке вещей. Даже наоборот, без AJAX трудно и представить себе некоторые сервисы.
Как работали обычные веб-приложения? Как правило, на событие (клик по ссылке или нажатие на кнопку) браузер реагировал отправкой запроса серверу. Когда с сервера приходил ответ, всё содержимое страницы полностью обновлялось.
Одна из проблем состояла в том, что при обновлении содержимого страницы веб-приложение переходит в новое состояние. Из информации о предыдущем состоянии сохраняются только данные, переданные в запросе. Чем более точная информация о прежнем состоянии системы требуется, тем больше данных необходимо пересылать в запросе.
Другим недостатком является необходимость пересылать повторяющиеся массивы данных клиенту после каждого события. Например, если пользователь ошибся при заполнении формы, то вместо короткого сообщения об ошибке приходится снова загружать и форму, и всю введённую ранее информации.
Современные браузеры, поддерживающие стандарты W3C DOM, позволяют вывести веб-приложение на новый уровень.
Схема взаимодействия остается почти такой же. Вот только отправляет запрос и получает ответ с сервера теперь скрипт на стороне клиента, а вместо обновления всей страницы - обновляется только ее часть (вместо обновления могут предприниматься иные действия, например, отправляться следующий запрос).
Веб-приложение получается распределенным, и часть логики находится на стороне клиента, а часть - на стороне сервера. Такие приложения и называют термином "AJAX Applications" (аббревиатура расшифровывается как Asynchronous Javascript And Xml Applications).
Объект XMLHTTPRequest
Для асинхронных запросов от клиента к серверу на стороне браузера служит специальный объект под названием XMLHTTPRequest.
Перечислим методы и свойства объекта, которые будут использованы далее:
- XMLHTTPRequest.open("method", "URL", async, "uname", "pswd") - создает запрос к серверу.
- method - тип запроса, например, GET
- URL - URL запроса, например http://localhost/file.xml
- async - если True, то будет использоваться асинхронный запрос, то есть выполнение скрипта продолжится после отправки запроса. В противном случае скрипт будет ожидать ответа от сервера, заморозив UI.
- uname, pswd - логин и пароль для простой веб-авторизации.
- XMLHTTPRequest.send("content") - отправляет запрос на сервер. Значением content могут быть данные для POST-запроса или пустая строка.
- XMLHTTPRequest.onreadystatechange - обработчик событий срабатывающий на каждое изменение состояния объекта. Состояния объекта могут быть следующими:
- 0 - до того как запрос отправлен (uninitialized)
- 1 - объект инициализирован (loading)
- 2 - получен ответ от сервера (loaded)
- 3 - соединение с сервером активно (interactive)
- 4 - объект завершил работу (complete)
- XMLHTTPRequest.responseText - возвращает полученные от сервера данные в виде строки.
- XMLHTTPRequest.responseXML - если ответ сервера пришел в виде правильного XML, возвращает XML DOM объект.
- XMLHTTPRequest.status - возвращает статус HTTP-ответа в виде числа. Например, 404 если запрашиваемая страница не была найдена на сервере.
Рассмотрим применение объекта на примере простого AJAX-приложения.
Поле SELECT с поиском
Предположим у нас есть таблица, в которой порядка миллиона записей. Пользователю необходимо выбрать всего одну запись из таблицы (реализация отношения "один ко многим"). Выбор пользователя является всего лишь одним из этапов заполнения большой веб-формы.
Естественно, для того, чтобы пользователь мог выбрать нужную запись из миллиона, нужны какие-то средства поиска этой самой записи. Например, простой текстовый поиск по наименованию.
В традиционном веб-приложении для этой цели пришлось бы использовать отдельную страницу и сохранять остальные данные формы в сессии пользователя, либо разбивать процесс заполнения формы на несколько этапов. В AJAX-приложении дополнительная страница не нужна.
Выбор записи будет реализован с помощью двух элементов веб-формы. Первый элемент - это текстовое поле, где пользователь вводит ключевое слово. Оно отсылается на сервер, а тот возвращает только те строки из таблицы, которые удовлетворяют условию поиска. Ответ сервера (в виде списка) помещается в поле SELECT, в котором пользователь и сделает окончательный выбор. Таким образом, при отправке всей формы на сервер попадет выбранное в поле SELECT значение в виде ID записи из большой таблицы.
В HTML выглядеть это может так:
<input type="text" onkeyup="lookup(this.value, 'id_select', 'http://localhost/cgi-bin/xmlhttp.cgi')" /> <select id="id_select" name="id_select"> <option selected="selected" value=""></option> </select>
На любое событие KeyUp (отжатие кнопки) в текстовом поле вызывается функция lookup ('текст', 'id-selecta', 'url')
function lookup(text, select_id, url) { // Получаем объект XMLHTTPRequest if(!this.http){ this.http = get_http(); this.working = false; } // Запрос if (!this.working && this.http) { var http = this.http; // Если в текстовом поле менее трёх // символов - не делаем ничего if (text.length <3 ) return; //добавляем закодированный текст //в URL запроса url = url + "?text="+encodeURIComponent(text); //создаём запрос this.http.open("GET", url, true); //прикрепляем к запросу функцию-обработчик //событий this.http.onreadystatechange = function() { // 4 - данные готовы для обработки if (http.readyState == 4) { fill(select_id, http.responseText); this.working = false; }else{ // данные в процессе получения, // можно повеселить пользователя //сообщениями // ЖДИТЕ ОТВЕТА } } this.working = true; this.http.send(null); } if(!this.http){ alert('Ошибка при создании XMLHTTP объекта!') } }
Как видно, в начале мы получаем XMLHTTP-объект с помощью функции get_http(). Затем поисковый текст кодируется в стиле URL и формируется GET-запрос к серверу. URL запроса в данном случае будет выглядеть приблизительно так: http://localhost/cgi-bin/xmlhttp.cgi?text=...
Скрипт на сервере, получив значение text, делает поиск в таблице и отсылает результат клиенту. В обработчике событий объекта XMLHTTP, когда данные от сервера получены и готовы к использованию, вызывается функция fill('select_id', 'data'), которая заполнит список SELECT полученными данными.
Функция get_http() - это кросс-браузерная реализация получения объекта XMLHTTP (в каждом браузере он получается по-своему). Её реализацию с комментариями вы можете легко найти в интернете, это, так сказать, пример из учебника.
function get_http(){ var xmlhttp; /*@cc_on @if (@_jscript_version >= 5) try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (E) { xmlhttp = false; } } @else xmlhttp = false; @end @*/ if (!xmlhttp && typeof XMLHttpRequest != 'undefined') { try { xmlhttp = new XMLHttpRequest(); } catch (e) { xmlhttp = false; } } return xmlhttp; }
Функция fill() получает на вход значение параметра ID списка SELECT, который необходимо заполнить, и сами данные, полученные с сервера.
Для простоты предположим, что данные с сервера мы получаем в виде таблицы, поля которой разделены символом табуляции 't', а строки - символом переноса строки 'n':
id1 t name1 n id2 t name2 n ...
На основании содержимого этой таблицы мы будем заполнять поле SELECT элементами OPTION.
function fill (select_id, data){ // поле SELECT в переменную в виде объекта var select = document.getElementById(select_id); // очищаем SELECT select.options.length = 0; // если данных нет - не делаем больше ничего if(data.length == 0) return; // в массиве arr - строки полученной таблицы var arr = data.split('n'); // для каждой строки for(var i in arr){ // в массиве val - поля полученной таблицы val = arr[i].split('t'); // добавляем новый объект OPTION к нашему SELECT select.options[select.options.length]= new Option(val[1], val[0], false, false); } }
Готово. Теперь для любой веб-формы приложения мы можем реализовать подобный выбор значения из многомиллионного списка, который для пользователя будет выглядеть как считанные нажатия клавиш. В локальной сети выбор происходит практически мгновенно. В случае нестабильного или низкоскоростного соединения с сервером, необходимо также оповещать пользователя о том, что загрузка данных с сервера еще не завершена. Полезно предусмотреть и средства для реакции на обрыв соединения.
Оставить комментарий
Комментарии
У меня почему-то всё равно выходит эта ошибка, не знаю, как её исправить. Посылаю заголовок header("Content-Type: text/plain; charset=window-1251") - толку нет, опять та же ошибка (браузер - IE 6). Может, ещё какой-то заголовок нужен, не подскажет кто?
Загрузка слоёв, и т.д.
Буду рад любой помощи
Написал библиотеку для автоматической генерации DOM (HTML) по шаблону. Теперь для использования JSON мне достаточно просто вызвать функцию build(json,tag,str), где json-полученный с помощью eval объект, tag-узел DOM для генерации содержимого, srt-шаблон. Теперь работаю с JSON просто и быстро.
p. s. Принимаю предложения о сотрудничестве(dojo-one@yandex.ru)
А надо мне всего-то узнать ответ 1 или 0.
помотие решить проблемму а не обойти ее
IE 6
function doLoad(uri,obj,dest) {
var req = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
req.onreadystatechange = function(){
alert(1);
if (req.readyState == 4) {
obj[dest] = req.responseText;
}
}
req.open("GET", uri+'&ctype=ptext');
req.send(null);
}
При отработке IE пишет что в скрипте ошибка с коментарием "Ошибка: Системная ошибка № -10728996748
Код: 0"
В ФФ код работает без проблем ,не считая ещё одного серьёзного минуса(проблемы с кодировками)