От переводчика: Вашему вниманию предлагается вторая статья из цикла «В ожидании Ext JS 4». В предыдущей статье разработчики Ext JS рассказывали о новой системе классов.
Пакет работы с данными отвечает за получение, декодирование и использование информации в Вашем приложении. Он является одной из тех частей библиотеки, на которую пришлось наибольшее количество улучшений и дополнений.
Пакет был полностью переписан для четвертой ветки фреймворка, но общая концепция не изменилась со времен предыдущих версий. Сегодня мы более детально познакомимся с этой технологией и посмотрим на ее возможности.
Пакет работы с данными в Ext JS 4 состоит из 43-х классов, но три из них особенно важны в сравнении с остальными – это Модель (Model), Хранилище (Store) и Прокси (Proxy). Они используются почти в каждом приложении вместе с классами-спутниками.
Базовым элементом пакета является класс Ext.data.Model, отвечающий за работу с моделью. Модель представляет собой набор неких данных в приложении – например, в электронном магазине могут быть модели для Пользователей (Users), Продукции (Products) и Заказов (Orders).
В самом упрощенном варианте Модель – это набор полей и их значений. Любой, кто работал с Ext JS 3, наверняка пользовался классом Ext.data.Record – предшественником Ext.data.Model. Давайте посмотрим, как мы сейчас создаем модель:
Обычно Модели используются в связке с Хранилищами – наборами экземпляров Моделей. Объявление Хранилища и загрузка в него данных – это просто:
Вот и все, что следует сделать для того, что бы загрузить набор экземпляров модели Пользователей с адреса 'users.json'. Мы настроили наше Хранилище с использованием AjaxProxy для чтения данных по указанному адресу и класса Ext.data.Reader для перекодировки данных. В нашем случае сервер возвращает ответ в формате JSON, потому мы и подготовили JsonReader для чтения ответа.
При помощи Хранилища можно отсортировать, отфильтровать и сгруппировать данные как локально, так и удаленно. В четвертой версии Ext JS отсутствует отдельный класс GroupingStore, так как стандартное Хранилище пригодно для множественной сортировки, фильтрации и группировки записей:
В только что созданном нами Хранилище данные будут отсортированы сначала по имени (полю name), а потом – по полю id; записи будут отфильтрованы так, что бы остались только Пользователи с именем 'Ed' и сгруппированы по возрасту (полю age). Если потребуется, то с легкостью можно изменить параметры сортировки, фильтрации или группировки в любое время, используя Store API.
Выше мы увидели, как Хранилище используют Прокси для загрузки данных и как Прокси могут быть настроены для использования Reader-классов для разбора ответа сервера. По сравнению с третьей версией, есть одно структурное изменение в Ext JS 4: Хранилище больше не содержит ссылок на Reader- и Writer-классы, которые перенесены в Прокси. Такой подход обеспечивает нам невероятное преимущество — Прокси теперь можно указывать непосредственно в Модели:
Имеем двойной выигрыш: во-первых, весьма вероятно, что каждое Хранилище, которое работает с моделью Пользователей, одинаково загружает данные – соответственно, нам не придется дублировать описания Прокси для Хранилищ. Во-вторых, мы теперь можем загружать и сохранять экземпляр модели без Хранилища:
Мы так же представляем Вашему вниманию несколько новых типов Прокси, которые используют возможности HTML 5 – LocalStorageProxy и SessionStorageProxy. Хотя старые браузеры и не поддерживают нововведения HTML 5, но новые Прокси настолько полезны, что множество приложений извлекут выгоду от их использования. Даже если у нас нет Прокси, который соответствует Вашим требованиям, то достаточно просто можно создать свой собственный.
Прокси – это не единственная новая возможность, добавленная к Моделям. Теперь можно задавать связи между Моделями при помощи нового Associations API. Большинство приложений работают с серьезным количеством разных Моделей, и Модели обычно связаны между собой на уровне прикладной логики. У блог-платформы могут быть модели для Пользователей (Users), Записей (Posts) и Комментариев (Comments). Каждый Пользователь публикует Записи, а Запись – получает Комментарии. Мы можем описать связи между моделями следующим образом:
Задача описания связей между разными моделями не является слишком сложной. Каждая модель может содержать описания любого количества связей с другими моделями, причем сами модели могут объявляться в любом порядке. После получения экземпляра модели мы можем отслеживать связанные данные – например, если мы хотим получит лог всех Комментариев к Записям, которые оставил определенный Пользователь, то можно использовать следующую конструкцию:
Каждая из связей типа «многие-к-одному» (hasMany) превращается в новую функцию, которая добавляется к Модели. Мы указываем, что у каждого Пользователя есть множество Записей. Это отношение описывается в функции user.posts(), которую мы встретили в предыдущем фрагменте кода. Вызов этой функции вернет Хранилище, сконфигурированное для работы с моделью Записей. В свою очередь, у модели Записей есть функция comments(), потому что задана связь «многие-к-одному» с моделью Комментариев.
Возможно, Вас удивил тот факт, почему мы задаем обработчик ‘success’ для вызова User.load, но не делаем этого во время доступа к записям и комментариям Пользователя. Считается, что все данные загружаются асинхронно с удаленного сервера. Этот факт подразумевает использование специальных success-обработчиков, которые автоматически вызываются в момент окончательной и успешной загрузки данных – как функция, описанная выше.
Библиотека может автоматически распознать и обработать связанные данные за один запрос, опираясь на описанные отношения между моделями. Вместо того, что бы сначала запросить данные для Пользователя, потом – о Записи, и еще по запросу для каждого Комментария, мы можем вернуть всю необходимую информацию в одном ответе сервера:
Можно легко настроить Прокси модели на получение данных из любого источника, а Reader-классы помогут справится с самыми заковыристыми форматами ответов. Начиная с Ext JS 3, Модели и Хранилища широко используются компонентами внутри фреймворка, в особенности – Таблицами (Grids), Деревьями (Tress) и Формами (Forms).
Мы подготовили для Вас небольшую онлайн-демонстрацию. В этом приложении используются те же Модели, которые описывались в статье, но код обрабатывает тестовые данные. Вы так же можете скачать демо одним архивом и экспериментировать самостоятельно. Сама библиотека сейчас в состоянии бета-версии, так что иногда могут встретиться ошибки, но в целом пакет обработки данных достаточно стабилен.
Что бы узнавать больше новостей из мира Sencha Touch и Ext JS, предлагаю Вам подписаться на нашу ежемесячную рассылку новостей, которая обычно содержит статьи, которые Вы нигде больше не найдете (даже в нашем блоге).
Пакет работы с данными отвечает за получение, декодирование и использование информации в Вашем приложении. Он является одной из тех частей библиотеки, на которую пришлось наибольшее количество улучшений и дополнений.
Пакет был полностью переписан для четвертой ветки фреймворка, но общая концепция не изменилась со времен предыдущих версий. Сегодня мы более детально познакомимся с этой технологией и посмотрим на ее возможности.
Что нового
Пакет работы с данными в Ext JS 4 состоит из 43-х классов, но три из них особенно важны в сравнении с остальными – это Модель (Model), Хранилище (Store) и Прокси (Proxy). Они используются почти в каждом приложении вместе с классами-спутниками.
Модели и Хранилища
Базовым элементом пакета является класс Ext.data.Model, отвечающий за работу с моделью. Модель представляет собой набор неких данных в приложении – например, в электронном магазине могут быть модели для Пользователей (Users), Продукции (Products) и Заказов (Orders).
В самом упрощенном варианте Модель – это набор полей и их значений. Любой, кто работал с Ext JS 3, наверняка пользовался классом Ext.data.Record – предшественником Ext.data.Model. Давайте посмотрим, как мы сейчас создаем модель:
Ext.regModel('User', { fields: [ {name: 'id', type: 'int'}, {name: 'name', type: 'string'} ] });
Обычно Модели используются в связке с Хранилищами – наборами экземпляров Моделей. Объявление Хранилища и загрузка в него данных – это просто:
new Ext.data.Store({ model: 'User', proxy: { type: 'ajax', url : 'users.json', reader: 'json' }, autoLoad: true });
Вот и все, что следует сделать для того, что бы загрузить набор экземпляров модели Пользователей с адреса 'users.json'. Мы настроили наше Хранилище с использованием AjaxProxy для чтения данных по указанному адресу и класса Ext.data.Reader для перекодировки данных. В нашем случае сервер возвращает ответ в формате JSON, потому мы и подготовили JsonReader для чтения ответа.
При помощи Хранилища можно отсортировать, отфильтровать и сгруппировать данные как локально, так и удаленно. В четвертой версии Ext JS отсутствует отдельный класс GroupingStore, так как стандартное Хранилище пригодно для множественной сортировки, фильтрации и группировки записей:
new Ext.data.Store({ model: 'User', sorters: ['name', 'id'], filters: { property: 'name', value : 'Ed' }, groupers: { property : 'age', direction: 'ASC' } });
В только что созданном нами Хранилище данные будут отсортированы сначала по имени (полю name), а потом – по полю id; записи будут отфильтрованы так, что бы остались только Пользователи с именем 'Ed' и сгруппированы по возрасту (полю age). Если потребуется, то с легкостью можно изменить параметры сортировки, фильтрации или группировки в любое время, используя Store API.
Прокси
Выше мы увидели, как Хранилище используют Прокси для загрузки данных и как Прокси могут быть настроены для использования Reader-классов для разбора ответа сервера. По сравнению с третьей версией, есть одно структурное изменение в Ext JS 4: Хранилище больше не содержит ссылок на Reader- и Writer-классы, которые перенесены в Прокси. Такой подход обеспечивает нам невероятное преимущество — Прокси теперь можно указывать непосредственно в Модели:
Ext.regModel('User', { fields: ['id', 'name', 'age'], proxy: { type: 'rest', url : '/users', reader: { type: 'json', root: 'users' } } }); //используем прокси модели new Ext.data.Store({ model: 'User' });
Имеем двойной выигрыш: во-первых, весьма вероятно, что каждое Хранилище, которое работает с моделью Пользователей, одинаково загружает данные – соответственно, нам не придется дублировать описания Прокси для Хранилищ. Во-вторых, мы теперь можем загружать и сохранять экземпляр модели без Хранилища:
//получаем ссылку на класс Пользователя (User) var User = Ext.getModel('User'); var ed = new User({ name: 'Ed Spencer', age : 25 }); //Мы можем сохранить Эда напрямую, без добавления его в Хранилище //потому что мы настроили специальный тип Прокси - RestProxy, который автоматически // пошлет POST запрос на изменение данных по адресу /users ed.save({ success: function(ed) { console.log("Saved Ed! His ID is "+ ed.getId()); } }); //Загружаем Пользователя 123 и что-то с ним делаем (по факту вызывается GET-запрос /users/123) User.load(123, { success: function(user) { console.log("Loaded user 123: " + user.get('name')); } });
Мы так же представляем Вашему вниманию несколько новых типов Прокси, которые используют возможности HTML 5 – LocalStorageProxy и SessionStorageProxy. Хотя старые браузеры и не поддерживают нововведения HTML 5, но новые Прокси настолько полезны, что множество приложений извлекут выгоду от их использования. Даже если у нас нет Прокси, который соответствует Вашим требованиям, то достаточно просто можно создать свой собственный.
Связи
Прокси – это не единственная новая возможность, добавленная к Моделям. Теперь можно задавать связи между Моделями при помощи нового Associations API. Большинство приложений работают с серьезным количеством разных Моделей, и Модели обычно связаны между собой на уровне прикладной логики. У блог-платформы могут быть модели для Пользователей (Users), Записей (Posts) и Комментариев (Comments). Каждый Пользователь публикует Записи, а Запись – получает Комментарии. Мы можем описать связи между моделями следующим образом:
Ext.regModel('User', { fields: ['id', 'name'], hasMany: 'Posts' }); Ext.regModel('Post', { fields: ['id', 'user_id', 'title', 'body'], belongsTo: 'User', hasMany: 'Comments' }); Ext.regModel('Comment', { fields: ['id', 'post_id', 'name', 'message'], belongsTo: 'Post' });
Задача описания связей между разными моделями не является слишком сложной. Каждая модель может содержать описания любого количества связей с другими моделями, причем сами модели могут объявляться в любом порядке. После получения экземпляра модели мы можем отслеживать связанные данные – например, если мы хотим получит лог всех Комментариев к Записям, которые оставил определенный Пользователь, то можно использовать следующую конструкцию:
//Получаем пользователя с ID 123 при помощи Прокси модели User User.load(123, { success: function(user) { console.log("User: " + user.get('name')); user.posts().each(function(post) { console.log("Comments for post: " + post.get('title')); post.comments().each(function(comment) { console.log(comment.get('message')); }); }); } });
Каждая из связей типа «многие-к-одному» (hasMany) превращается в новую функцию, которая добавляется к Модели. Мы указываем, что у каждого Пользователя есть множество Записей. Это отношение описывается в функции user.posts(), которую мы встретили в предыдущем фрагменте кода. Вызов этой функции вернет Хранилище, сконфигурированное для работы с моделью Записей. В свою очередь, у модели Записей есть функция comments(), потому что задана связь «многие-к-одному» с моделью Комментариев.
Возможно, Вас удивил тот факт, почему мы задаем обработчик ‘success’ для вызова User.load, но не делаем этого во время доступа к записям и комментариям Пользователя. Считается, что все данные загружаются асинхронно с удаленного сервера. Этот факт подразумевает использование специальных success-обработчиков, которые автоматически вызываются в момент окончательной и успешной загрузки данных – как функция, описанная выше.
Загрузка связанных данных
Библиотека может автоматически распознать и обработать связанные данные за один запрос, опираясь на описанные отношения между моделями. Вместо того, что бы сначала запросить данные для Пользователя, потом – о Записи, и еще по запросу для каждого Комментария, мы можем вернуть всю необходимую информацию в одном ответе сервера:
{ id: 1 name: 'Ed', posts: [ { id : 12, title: 'All about data in Ext JS 4', body : 'One of the areas that has seen the most improvement in Ext JS 4...', comments: [ { id: 123, name: 'S Jobs', message: 'One more thing' } ] } ] }
Можно легко настроить Прокси модели на получение данных из любого источника, а Reader-классы помогут справится с самыми заковыристыми форматами ответов. Начиная с Ext JS 3, Модели и Хранилища широко используются компонентами внутри фреймворка, в особенности – Таблицами (Grids), Деревьями (Tress) и Формами (Forms).
Демонстрация возможностей
Мы подготовили для Вас небольшую онлайн-демонстрацию. В этом приложении используются те же Модели, которые описывались в статье, но код обрабатывает тестовые данные. Вы так же можете скачать демо одним архивом и экспериментировать самостоятельно. Сама библиотека сейчас в состоянии бета-версии, так что иногда могут встретиться ошибки, но в целом пакет обработки данных достаточно стабилен.
Что бы узнавать больше новостей из мира Sencha Touch и Ext JS, предлагаю Вам подписаться на нашу ежемесячную рассылку новостей, которая обычно содержит статьи, которые Вы нигде больше не найдете (даже в нашем блоге).
