ExtJs. Один запрос, несколько Ext.data.Store.
Не так давно я рассказывал о библиотеке ExtJs, ей же будет посвящена сегодняшняя заметка. Эта заметка расчитана на подготовленного читателя, который уже разобрался с базовыми понятиями. Но и новичку будет полезно взглянуть на то, что предлагает эта библиотека, возможно захочется стать подготовленным =) Комментарии будут подробными.
Стоит заметить, что речь пойдет о второй версии, которая сейчас значиться Release Candidate 1 и доступна для скачивания по ссылке
Сегодня речь пойдет об Ext.data.Store. Объект удачный и используется во множестве виджетов в качестве источника данных. Обычный подход заключается в том, чтобы создать подгружающий себя объект и вызывать метод load(), для его загрузки.
//Инициализируем соединение
var rCon = new Ext.data.Connection({
//Урл "кормящего" файла =)
url: '/data.php',
//Метод
method: 'POST',
//Параметры, которые передадутся в запросе
extraParams: {'act' : 'get_requests'}
});
//Само хранилище
var rDs = new Ext.data.Store({
//Прокси с соединением, созданным выше
proxy: new Ext.data.HttpProxy(rCon),
//"Читатель" ответов, приходящих в формате JSON
reader: new Ext.data.JsonReader({
//Какое свойство читать
root: 'requests',
//Какое свойство отвечает за кол-во записей
totalProperty: 'total_requests',
//Поля записей
fields: [
'requests_key',
'requests_name'
]
})
});
rDs.load();
Так выглядит обычное создание и загрузка хранилища. При вызове метода load() идет асинхронных запрос к серверу, получаются данные и далее с ними делается то, что нужно. Вcё замечательно. Есть одно "но". Хранилище в силу своей универсальности используется и для ComboBox - выпадающих списков в формах. А этих самых ComboBox в одной форме может быть много. У меня, например 19 =) Таким образом, реализуя приведенную выше схему, мы получим 19 асинхронных вызовов. А это не очень хорошо.
Известно, что у браузеров есть ограничение на количество одновременных вызовов. Благодаря комментариям, мы знаем, что это 3 для FF и 2 для IE. И мы получаем сильное снижение производительности. Это если не брать в расчет проблемы с обработкой 19 вызовов, и синхронизации загрузки с отображением. Ведь если не успеют загрузиться хранилища, а мы уже начнем показывать форму, будет не очень красиво.
Продумав это всё в голове, я пришел к выводу, что надо действовать по-другому. Надо наполнить все 19 хранилищ за один запрос. Поиски на форуме не привели к нахождению решения. Хотя пару идей я получил. В рецепте, приведенном ниже будет использован метод loadData(), вместо load(). Который просто загружает уже пришедшие данные в хранилище, никуда не обращаясь. Я не буду приводить код для 19 хранилищ, приведу для двух.
//Создаем record. Пригодится для "читателя" хранилища.
dsDataRecord = new Ext.data.Record.create([
//Пишем название свойства и мапим его
//на второй элемент массива пришедших данных
{name : 'data_key', mapping : 1},
{name : 'data_name', mapping: 2}
]);
//Хранилище номер раз.
dataStore = new Ext.data.Store({
//Читатель на этот раз "массивный" а не JSON =)
reader: new Ext.data.ArrayReader({
//Первый элемент массива для упорядочивания. Он уникальный.
id: 0
//Наш record.
}, dsDataRecord)
});
//Создаем record. Пригодится для "читателя" хранилища.
dsDigitRecord = new Ext.data.Record.create([
//Пишем название свойства и мапим его
//на второй элемент массива пришедших данных
{name : 'digit_key', mapping : 1},
{name : 'digit_name', mapping : 2}
]);
//Хранилище номер два.
digitStore = new Ext.data.Store({
//Читатель на этот раз "массивный" а не JSON =)
reader: new Ext.data.ArrayReader({
//Первый элемент массива для упорядочивания. Он уникальный.
id: 0
//Наш record.
}, dsDigitRecord)
});
//AJAX-запрос на все данные
comboStoreRequest = Ext.Ajax.request({
//Урл "кормящего файла"
url: 'data.php',
//В случае успешного запроса
success: function(result){
//Преобразуем JSON-ответ в объект
comboStore = Ext.util.JSON.decode(result.responseText);
//Загрузим массив данных первое хранилище
dataStore.loadData(comboStore.data);
//Загрузим массив данных во второе хранилище
digitStore.loadData(comboStore.digit);
},
//Метод
method: 'POST',
//Параметры вызова
params: {act : 'get_data'}
});
Приведенный код тоже не слишком сложен. Самое интересное, для меня, было сформировать теперь выдачу с сервера JSON-данных, чтобы их "прожевал" ArrayReader. И сделал из них массивы, приемлемые для загрузки в хранилище.
На основе документации, можно прийти к выводу, что ArrayReader ожидает данные в виде объектов вида:
[[1, key1, name1],[2, key2, name2],[3, key3, name3]]
Значит в PHP нам необходимо иметь массив, повторяющий приведенную структуру и применить к нему json_encode()
<?php
//Массив с данными
$data_array[] = array(1, "data_key1", "data_name1");
$data_array[] = array(2, "data_key2", "data_name2");
$data_array[] = array(3, "data_key3", "data_name3");
//Выводим JSON-массив
echo json_encode($array);
?>
Первый пункт выполнен. Этими данными вполне можно "накормить" один ArrayReader. А у нас их два. А ответ от сервера один. Значит надо наши массивы упаковать как свойства объекта. И обращаться к ним при загрузке в хранилище. Для этого на сервере нужен следующий PHP-код:
<?php
//Первый массив
$data_array[] = array(1, "data_key1", "data_name1");
$data_array[] = array(2, "data_key2", "data_name2");
$data_array[] = array(3, "data_key3", "data_name3");
//Второй массив
$digit_array[] = array(1, "digit_key1", "digit_name1");
$digit_array[] = array(2, "digit_key2", "digit_name2");
$digit_array[] = array(3, "digit_key3", "digit_name3");
//Собираем всё в один массив.
$data = array('data' => $data_array, 'digit' => $digit_array);
//Выводим окончательный ответ.
echo json_encode($data);
?>
Готово. Теперь мы передаем JSON-объект с двумя свойствами, которые являются массивами данных. И мы можем загрузить их в наши dataStore. Задача выполнена =)