Не так давно я рассказывал о библиотеке 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. Задача выполнена =)