При создании компонент интерфейса часто нужен AJAX. Например - SELECT с подгружающимся списком, поле с автозаполнением, дерево с подгружающимися узлами и т.п.
Эта статья посвящена конкретному примеру удобной и универсальной реализации AJAX для компонента интерфейса. Она дает общие рамки, можно даже сказать "фреймворк" для создания таких виджетов.
Например, рассмотрим селект, загружающий данные с сервера. С точки зрения AJAX он почти ничем не отличается от подгружающегося дерева или таблицы.
Общий поток выполнения при AJAX-подгрузке данных, начиная от пустого селекта:
|
|
|
Список телодвижений при загрузке:
Для создания компоненты интерфейса используем функцию, которая принимает id узла SELECT и возвращает построенный компонент.
Код настолько простой, что я привожу его сразу целиком, а чуть ниже - разбираю каждый метод по отдельности.
function ajaxSelect(id) {
var element = document.getElementById(id)
var onLoaded = function(data) {
var i=0
for(var key in data) {
var label = data[key]
element.options[i++] = new Option(label, key)
}
}
var onLoadError = function(error) {
var msg = "Ошибка "+error.errcode
if (error.message) msg = msg + ' :'+error.message
alert(msg)
}
var showLoading = function(on) {
element.disabled = on
}
var onSuccess = function(data) {
if (!data.errcode) {
onLoaded(data)
showLoading(false)
} else {
showLoading(false)
onLoadError(data)
}
}
var onAjaxError = function(xhr, status){
showLoading(false)
var errinfo = { errcode: status }
if (xhr.status != 200) {
// может быть статус 200, а ошибка
// из-за некорректного JSON
errinfo.message = xhr.statusText
} else {
errinfo.message = 'Некорректные данные с сервера'
}
onLoadError(errinfo)
}
return {
load: function(url) {
showLoading(true)
while (element.firstChild) {
element.removeChild(element.firstChild)
}
$.ajax({ // для краткости - jQuery
url: url,
dataType: "json",
success: onSuccess,
error: onAjaxError,
cache: false
})
}
}
}
Как это использовать:
<select id="ajax-select"></select>
select = ajaxSelect('ajax-select')
select.load('/ajax/ui/options.php')
А теперь - разберем все по порядку.
При стиле ООП "фабрика объектов" - приватные переменные обозначаются var, а доступные извне описываются как свойства возвращаемого return объекта.
Инициализация осуществляется непосредственно вызовом функции, без new:
select = ajaxSelect('...ID узла DOM...')
Так что функции onSuccess, onAjaxError, showLoading - приватные, а функция load - публичная.
Два первых метода onLoaded и onLoadError - основные. Любая AJAX-загрузка приводит к одному из них.
{1:"Яблоко",2:"Дыня"}
превращается в опции селекта:
<option val="1">Яблоко</option> <option val="2">Дыня</option>
Использованы стандартные методы работы с DOM (new Option).
error должен содержать свойство errcode - код ошибки, например "timeout" или "15541" и, дополнительно, может предоставлять более подробное описание ошибки в свойстве message.
В нашем примере - выдает форматированное сообщение об ошибке.
Метод индикации загрузки в примере просто включает-выключает селект.
Ничто не мешает добавить красивый анимированный значок загрузки. Желательно делать это через добавление CSS-класса к родительскому элемента select'а.
Получится что-то типа:
HTML-код для такой индикации:
<style>
.loading {
padding-left:20px;
background: url(/http/javascript.ru/ajax/ui/blue-loading.gif) left no-repeat;
}
</style>
<span class="loading">
<select disabled="disabled"></select>
</span>
Как правило, ставит/убирает один CSS-класс.
Следующие два метода являются коллбэками для AJAX-запроса.
Чтобы сообщить о произошедшей ошибке, серверу достаточно передать, например, такой ответ:
{
errcode: 500,
message: "Апдейт базы данных. Повторите запрос через 10 минут"
}
Обратите внимание на последовательность вызовов. Если все в порядке, то сначала вызывается обработка данных onLoaded - и только потом отключается индикация showLoading(false), чтобы посетитель увидел сразу заполненный селект.
Если произошла ошибка - удобнее сделать наоборот: сначала убрать индикацию загрузки, а затем вывести сообщение.
Вызов $.ajax автоматически интерпретирует ответ сервера как JSON - и если с этим проблемы, то хотя XmlHttpRequest выполнился успешно, но $.ajax вызывает коллбэк для ошибки и ставит status="parsererror".
Удобно то, что где бы ни произошла ошибка: во время выполнения XmlHttpRequest-запроса, или на сервере, или при разборе JSON - вызовется единый обработчик onLoadError.
Ну и, наконец, единственный публичный метод:
showLoading и удаляет всех детей, т.е очищает элемент.Работающий селект можно посмотреть в действии:
Кнопки в этом примере инициализуются так:
$(document).ready(function() {
var select = ajaxSelect('ajax-select');
// урл, всегда выдающий пару разных фруктов
document.getElementById('ajax-select-load-options').onclick =
function() { select.load('/ajax/ui/options.php') }
// урл, всегда выдающий ошибку
document.getElementById('ajax-select-load-error').onclick =
function() { select.load('/ajax/ui/error.php') }
});
Разумеется, никто не мешает передавать более сложный URL, добавлять туда id и другую полезную информацию.
Вы: