От переводчика: Вашему вниманию предлагается вторая статья из цикла «В ожидании 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, предлагаю Вам подписаться на нашу ежемесячную рассылку новостей, которая обычно содержит статьи, которые Вы нигде больше не найдете (даже в нашем блоге).