Pull to refresh

В ожидании Ext JS 4: Пакет работы с данными

Reading time6 min
Views4.4K
Original author: Ed Spencer
От переводчика: Вашему вниманию предлагается вторая статья из цикла «В ожидании 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. Давайте посмотрим, как мы сейчас создаем модель:

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, предлагаю Вам подписаться на нашу ежемесячную рассылку новостей, которая обычно содержит статьи, которые Вы нигде больше не найдете (даже в нашем блоге).
Tags:
Hubs:
Total votes 23: ↑20 and ↓3+17
Comments18

Articles