Примечание редактора: команда Ember.js перешла к ускоренному графику выпуска, и на эту дату публикации находятся в версии 1.2.0. Этот учебник был написан до версии 1.0, но многие концепции все еще применимы. Мы делаем все возможное, чтобы своевременно вводить контент, и такие ситуации случаются время от времени. Мы будем работать, чтобы обновить это в будущем.
В третьей части моей серии Ember я показал вам, как вы можете взаимодействовать с данными, используя основной базовый класс Ember.Object
для создания объектов, которые определяют методы и свойства, которые действуют как обертка для ваших данных. Вот пример:
01
02
03
04
05
06
07
08
09
10
11
12
|
App.Item = Ember.Object.extend();
App.Item.reopenClass({
all: function() {
return $.getJSON(‘http://api.ihackernews.com/page?format=jsonp&callback=?’).then(function(response) {
var items = [];
response.items.forEach( function (item) {
items.push( App.Item.create(item) );
});
return items;
});
|
В этом коде мы создаем подкласс Ember.Object
с помощью « Ember.Object
extend()
» и создаем определяемый пользователем метод с именем « all()
», который отправляет Hacker News запрос на результаты его новостной ленты в формате JSON.
Хотя этот метод определенно работает и даже продвигается в дискурсе на основе Ember в качестве способа его выполнения, он требует от вас конкретизации и предоставления API, с которым вы хотите ссылаться на данные. Большинство сред MVC, как правило, включают ORM-подобные возможности, поэтому, если вы привыкли к Rails, например, вы будете очень хорошо знакомы с преимуществами ActiveRecord, который помогает управлять и выполнять тяжелую работу по взаимодействию с данными.
Команда Ember хотела сделать то же самое, но их основной задачей было сначала выпустить стабильную версию основной платформы v1, чтобы обеспечить возможность создания дополнительных компонентов на стабильной основе. Я на самом деле аплодирую этому и упомянул тот факт, что из-за этого вам следует воздерживаться от использования Ember Data.
Теперь, когда вышел Ember RC8, а v1, похоже, не за горами, я почувствовал, что сейчас самое время начать изучать Ember Data и посмотреть, что он предлагает.
Ember Data
Первое, что я хочу подчеркнуть, — это то, что Ember Data находится в стадии разработки и во многом так же, как Ember начал, вероятно, в ближайшие несколько месяцев произойдет ряд серьезных изменений API. Хотя это не идеально, важно начать смотреть на то, как вы бы структурировали свои приложения, используя библиотеку. Чтобы дать вам хорошее описание того, что предоставляет Ember Data, я скопировал хорошо написанное описание со страницы GitHub:
Ember Data — это библиотека для загрузки данных из постоянного уровня (например, JSON API), сопоставления этих данных с набором моделей в вашем клиентском приложении, обновления этих моделей и последующего сохранения изменений обратно в постоянный уровень. Он предоставляет множество возможностей, которые вы найдете в серверных ORM, таких как ActiveRecord, но разработан специально для уникальной среды JavaScript в браузере.
Итак, как я уже говорил, это предназначено для отвлечения от множества сложностей работы с данными.
Использование Ember Data
Если вы читали мои предыдущие уроки, вы должны быть хорошо знакомы с тем, как настроить страницу для использования Ember. Если вы этого не сделали, перейдите на домашнюю страницу Ember.js и возьмите Starter Kit. Вы можете найти его прямо в середине страницы, так как он отображается с помощью большой кнопки. Это даст вам самую последнюю версию Ember, которая вам понадобится для работы с Ember Data. Самый простой способ получить загружаемую версию Ember Data — перейти к документации API для models
, прокрутить до конца и загрузить библиотеку. Кроме того, вы можете перейти на страницу builds
чтобы просмотреть последние сборки любой библиотеки, связанной с Ember.
Добавить Ember Data так же просто, как добавить еще один JavaScript-файл к миксу, например:
1
2
3
4
5
|
<script src=»js/libs/jquery-1.9.1.js»></script>
<script src=»js/libs/handlebars-1.0.0.js»></script>
<script src=»js/libs/ember-1.0.0-rc.8.js»></script>
<script src=»js/libs/ember-data.js»></script>
<script src=»js/app.js»></script>
|
Теперь это дает вам доступ к объектам, методам и свойствам Ember Data.
Без какой-либо конфигурации Ember Data может загружать и сохранять записи и связи, обслуживаемые через RESTful JSON API, при условии соблюдения определенных соглашений.
Определение магазина
Ember использует специальный объект, называемый store
для загрузки моделей и извлечения данных и основан на классе Ember DS.Store
. Вот как бы вы определили новый магазин:
1
2
3
|
App.Store = DS.Store.extend({
…
});
|
Если вы помните из моих предыдущих статей, "App"
— это просто пространство имен, созданное для объектов уровня приложения, методов и свойств приложения. Хотя это не зарезервированное слово в Ember, я призываю вас использовать то же имя, что и почти в каждом учебном пособии, и в демоверсии, которую я видел, оно используется для согласованности.
Магазин, который вы создадите, будет содержать созданные вами модели и будет служить интерфейсом с сервером, который вы определили в своем адаптере. По умолчанию Ember Data создает и связывает с вашим магазином адаптер REST на основе класса DS.RestAdapter
. Если вы просто определили приведенный выше код, по умолчанию к нему будет привязан адаптер. Магия угасания во всей красе. Вы также можете использовать адаптер Fixture, если вы работаете с данными в памяти (например, JSON, который вы загружаете из кода), но поскольку речь идет о вызовах API, адаптер REST является более подходящим.
Вы также можете определить свой собственный адаптер для тех ситуаций, когда вам нужно больше настраиваемого контроля взаимодействия с сервером, используя свойство adapter
в объявлении вашего магазина:
1
2
3
|
App.Store = DS.Store.extend({
adapter: ‘App.MyCustomAdapter’
});
|
Определение моделей
Код, который я перечислил в начале этого урока, был примером того, как использовать Ember.Object
для создания моделей для вашего приложения. Ситуация немного меняется, когда вы определяете модели через Ember Data. Ember Data предоставляет еще один объект с именем DS.Model
который вы создаете подкласс для каждой модели, которую хотите создать. Например, взяв код сверху:
1
|
App.Item = Ember.Object.extend();
|
Теперь это будет выглядеть так:
1
|
App.Item = DS.Model.Extend()
|
Не большая разница с точки зрения внешнего вида, но большая разница с точки зрения функциональности, поскольку теперь у вас есть доступ к возможностям адаптера REST, а также к встроенным взаимосвязям Ember Data, таким как один к одному, один ко многим и более. Основное преимущество, тем не менее, заключается в том, что Ember Data предоставляет возможности для взаимодействия с вашими данными через ваши модели, а не для того, чтобы вам приходилось создавать свои собственные. Снова ссылаемся на код сверху:
01
02
03
04
05
06
07
08
09
10
|
App.Item.reopenClass({
all: function() {
return $.getJSON(‘http://api.ihackernews.com/page?format=jsonp&callback=?’).then(function(response) {
var items = [];</p>
response.items.forEach( function (item) {
items.push( App.Item.create(item) );
});
return items;
});
|
Хотя мне пришлось создать собственный метод для возврата всех результатов из моего вызова JSON, Ember Data предоставляет метод find()
который делает именно это, а также служит для фильтрации результатов. По сути, все, что мне нужно сделать, это сделать следующий вызов, чтобы вернуть все мои записи:
1
|
App.Item.find();
|
Метод find()
отправляет запрос Ajax на URL.
Это именно то, что привлекает так много разработчиков в Ember; предусмотрительность, чтобы сделать вещи проще.
Следует иметь в виду, что в модели важно определить атрибуты, которые вы планируете использовать позже (например, в своих шаблонах). Это легко сделать:
1
2
3
|
App.Post = DS.Model.extend({
title: DS.attr(‘string’)
});
|
В моем демонстрационном приложении я хочу использовать свойство title, возвращаемое через JSON, поэтому, используя метод attr()
, укажите, какие атрибуты модель имеет в моем распоряжении.
Я хочу упомянуть одну вещь: Ember Data невероятно требователен к структуре возвращаемого JSON. Поскольку Ember использует структуры каталогов для идентификации определенных частей ваших приложений (помните соглашения об именах, которые мы обсуждали в моей первой статье Ember ?), Он делает определенные предположения относительно структуры данных JSON. Требуется наличие именованного корня, который будет использоваться для идентификации возвращаемых данных. Вот что я имею в виду:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
{
‘posts’: [{
‘id’: 1,
‘title’: ‘A friend of mine just posted this.’,
‘url’: ‘http://i.imgur.com/9pw20NY.jpg’
}]
}[js]
<p>If you had defined it like this:</p>
[js]{
{
‘id’: ‘1’,
‘title’: ‘A friend of mine just posted this.’,
‘url’: ‘http://i.imgur.com/9pw20NY.jpg’
},
{
‘id’: ‘2’,
‘title’: ‘A friend of mine just posted this.’,
‘url’: ‘http://i.imgur.com/9pw20NY.jpg’
},
}
|
Ember Data полностью отказался бы и выдал бы следующую ошибку:
Ваш сервер вернул хэш с идентификатором ключа, но у вас нет сопоставления для него.
Причина в том, что поскольку модель называется "App.Post"
, Ember Data ожидает найти URL-адрес «posts», из которого она будет извлекать данные. Так что, если я определил свой магазин как таковой:
1
2
3
|
App.Store = DS.Store.extend({
url: ‘http://emberdata.local’
});
|
и моя модель вот так:
1
2
3
|
App.Post = DS.Model.extend({
title: DS.attr(‘string’)
});
|
Ember Data предполагает, что запрос Ajax, сделанный методом find()
будет выглядеть следующим образом:
1
|
http://emberdata.local/posts
|
И если вы делаете запрос на конкретный идентификатор (например, find (12)), он будет выглядеть так:
1
|
http://emberdata.local/posts/12
|
Эта проблема привела меня в замешательство, но поиск занял много дискуссий. Если вы не можете настроить результаты JSON таким образом, вам придется создать собственный адаптер, чтобы преобразовать результаты, чтобы правильно их сериализовать, прежде чем использовать их. Я не буду освещать это здесь, но планирую изучить больше этого в ближайшее время.
Демо-приложение
Я специально хотел, чтобы этот учебник был простым, потому что я знаю, что Ember Data меняется, и я хотел дать краткий обзор того, что он предоставил. Поэтому я создал быстрое демонстрационное приложение, которое использует Ember Data для извлечения данных JSON с моего локального сервера. Давайте посмотрим на код.
Сначала я создаю пространство имен своего приложения (которое вы бы сделали для любого приложения Ember):
1
2
|
// Create our Application
App = Ember.Application.create({});
|
Затем я определяю свое хранилище данных и объявляю url
откуда модель будет извлекать данные:
1
2
3
|
App.Store = DS.Store.extend({
url: ‘http://emberdata.local’;
});
|
В модели я указываю атрибут: title
, который я буду использовать в своем шаблоне позже:
1
2
3
4
|
// Our model
App.Post = DS.Model.extend({
title: DS.attr(‘string’)
});
|
Наконец, я связываю модель с маршрутом через крюк модели. Обратите внимание, что я использую предопределенный метод Ember Data find()
для немедленного извлечения моих данных JSON при запуске приложения:
1
2
3
4
5
6
|
// Our default route.
App.IndexRoute = Ember.Route.extend({
model: function() {
return App.Post.find();
}
});
|
В шаблоне для корневой страницы (индекс) я использую директиву #each
Handlebars, чтобы просмотреть результаты моих данных JSON и отобразить заголовок каждого из моих сообщений:
1
2
3
4
5
6
7
8
|
<script type=»text/x-handlebars» data-template-name=»index»>
<h2>My Posts</h2>
<ul>
{{#each post in model}}
<li>{{post.title}}</li>
{{/each}}
</ul>
</script></p>
|
Это оно! Нет вызова Ajax или специальных методов для работы с моими данными. Ember Data позаботились о том, чтобы сделать вызов XHR и сохранить данные.
Плавник
Это невероятно упрощенно, и я не хочу, чтобы вы поверили, что это единороги и щенки. Ember.Object
через процесс работы с Ember Data, я захотел вернуться к использованию Ember.Object
где у меня было больше контроля. Но я также осознаю, что ведется большая работа по улучшению данных Ember, особенно в том, как они управляют различными результатами данных. Поэтому важно, по крайней мере, запустить процесс понимания того, как это работает, и даже предложить конструктивную обратную связь команде.
Поэтому я призываю вас присоединиться и начать с ним возиться, особенно те, которые имеют очень сильный фон ORM и могут помочь сформировать направление Ember Data. Сейчас самое подходящее время для этого.