Ввиду недавнего выхода Ember.js 1.0 настало время для практического его использования. Эта статья представляет собой подробное введение в Ember.js и содержит всю необходимую информацию для новичков, которые хотят узнать больше об этом фреймворке.
Многие пользователи часто говорят о трудностях обучения, но как только вы преодолеете все испытания, перед вами откроется огромный спектр возможностей Ember.js. Я оказался в аналогичной ситуации. Несмотря на то, что существуют официальные руководства, которые являются достаточно точными и новыми, я попытался написать статью, которая описывает для новичков все особенности Ember.js понятным и доступным языком.
Во-первых, мы постараемся разобраться в основных понятиях. Далее, мы будем шаг за шагом углубляться в процесс обучения, в результате которого вы сможете создать простое веб-приложение с помощью Ember.js и Ember-Data, которое будет хранить все данные в Ember слое. Затем мы рассмотрим, как элементы views
и components
помогают организовать взаимодействие с пользователем. Наконец, мы подробно рассмотрим Ember-Data и шаблон предварительной компиляции.
Знаменитый маленький талисман Ember по имени Tomster. (Источник изображения).
Нестилизированная демо-версия ниже поможет вам следить за каждым этапом урока. Усовершенствованная демо-версия, в целом такая же, но с намного большим количеством CSS кода и анимацией, а также с полностью адаптивным пользовательским интерфейсом при отображении на небольших экранах.
Нестилизированная демо-версия; Исходный код; Усовершенствованная демо-версия
Содержание статьи.
- Определение основных концепций.
- Построение простейшей CRUD.
- Эскиз нашего приложения.
- То, что вам потребуется для начала работы.
- Структура каталога файлов.
- Необходимо ли использовать шаблоны предварительной компиляции?
- Настройка модели с помощью FixtureAdapter в Ember-Data.
- Демонстрационный пример создания маршрутизатора.
- Шаблон приложения.
- Пользовательский маршрут.
- Объектное управление в сравнении с массивом.
- Отображение числа пользователей.
- Вычисленные свойства.
- Перенаправление из классификационной страницы.
- Маршрут для одного пользователя.
- Редактирование данных пользователя.
- Наше первое действие.
- TransitionTo или TransitionToRoute?
- Сохранение пользовательских изменений.
- Удаление пользователя.
- Добавление пользователя.
- Форматирование данных с помощником.
- Форматирование данных со связанными помощниками.
- Переключение к LocalStorage адаптеру.
- Экспериментирование с отображением.
- Что такое Ember-Data.
- Что такое предварительная компиляция Handlebars (рулевой) шаблона?
- Вывод.
Определения основных концепций.
На рисунке ниже показано, каким образом взаимодействуют друг с другом маршрутизаторы, контроллеры, представления, шаблоны и модели.
Давайте разберемся с этими понятиями. Если вы хотите узнать больше, посетите соответствующий раздел официальных руководств:
Модели.
Допустим, что наше приложение обслуживает потребности определенной группы пользователей. Эти пользователи и их информация будет моделью. Их следует рассматривать как базы данных. Модели могут быть найдены и обновлены благодаря использованию AJAX обратных вызовов внутри вашего маршрута, или вы можете воспользоваться Ember-Data (хранения данных аппаратного слоя), что значительно упрощает поиск, обновление и сохранение моделей через REST API.
Маршрутизатор.
С помощью элемента Router
можно создавать маршруты. Router
позволяет получить краткий обзор всех ваших маршрутов. Маршруты – это URL представления ваших объектов приложения (например, маршрут posts
отобразит коллекции сообщений). Целью маршрута является запрос к модели из model
, что позволяет сделать его доступным в контроллере и в шаблоне. Маршруты могут быть также использованы для установки в свойствах контроллера, для выполнения событий и действий, а также для подключения конкретного шаблона для использования конкретным контроллером. Последняя, но не менее важная возможность заключается в том, что model
может возвращать значение, поэтому вы можете реализовать LoadingRoute
, которая будет ожидать пока модель примет решение об асинхронной загрузке по сети.
Контроллеры.
Сначала controller
извлекает модель из route
. Данная операция позволяет создать связь между моделью и представлением или моделью и шаблоном. Допустим, вам необходимо создать удобный метод или функцию переключения между режимом редактирования и обычным режимом. В этом случае идеальным вариантом стало бы использование такого метода, как goIntoEditMode()
и closeEditMode()
и это именно тот случай, для которого могут быть использованы контроллеры.
Ember.js автоматически создает контроллеры, если вы их не объявили. Например, вы можете создать user
шаблон с UserRoute
; а если вы не создадите UserController
(ну, к примеру, вы не предполагаете его где-либо использовать), то Ember.js самостоятельно сгенерирует его для вас (в памяти). Ember Inspector, расширение для Chrome может помочь вам отслеживать все созданные контроллеры.
Представления.
Представления – это конкретные части вашего приложения (визуальные части, которые пользователь может видеть в браузере). Элемент View
связан с Controller
, Handlebars template
и Route
. Определить разницу между представлениями и шаблонами может быть сложнее. Вы будете иметь дело с представлениями в тех случаях, когда захотите обработать события или некоторые пользовательские взаимодействия, которыми невозможно управлять с помощью шаблонов. У них есть очень удобный didInsertElement
метод, с помощью которого вы можете достаточно легко экспериментировать с jQuery. Кроме того, они будут чрезвычайно полезны в тех случаях, когда вам нужно создать многоразовые представления, такие как модальности, сборщики информации и поля с автозаполнением.
Компоненты.
Component
представляет собой нечто аналогичное элементу View
, но только полностью изолированному и который не имеет доступа к окружающему контексту. Это отличный способ для создания повторно используемых компонентов вашего приложения. Кнопка Twitter, пользовательская область выбора и любые многоразово используемые графики – все это наиболее яркие примеры компонентов. Идея использования компонентов настолько приглянулась разработчикам, что W3C (консорциум World-Wide Web; в него входят около 400 членов, среди которых корпорации Apple, AT&T, America Online, CompuServe, Hewlett Packard, IBM, Microsoft, Netscape Communications, Sony, Xerox и многие другие компании; задача консорциума – создание и продвижение единых стандартов (таких как HTML, XML и др.), расширяющих функциональность Web) всерьез начали прорабатывать с командой Ember вариант создания спецификации пользовательского элемента.
Шаблоны.
Проще говоря, мы должны получить шаблон, который позволяет просмотреть HTML разметку. Он выводит модель данных и автоматически обновляется, когда происходят какие-либо изменения в модели. Ember.js использует Handlebars, легкий шаблонный движок, который также поддерживается командой Ember. Он использует обычную для шаблонов логику с командами if
и else
, циклами и форматированием helpers
и все в таком же роде. Шаблоны могут быть предварительно скомпилированы (если вы хотите аккуратно организовать их в виде отдельных .hbs
или .handlebars
файлов) или сразу же записаны в <script type="text/x-handlebars"><script>
тег на HTML-странице. Перейдите в раздел предварительная компиляция шаблонов, где вы можете проанализировать все более подробно.
Помощники.
Handlebars помощники – это функции, которые позволяют изменять данные перед прорисовкой на экране, например, для улучшения формата даты Mon Jul 29 2013 13:37:39 GMT+0200 (CEST)
. В шаблоне, дата может быть записана как {{date}}
. Допустим, у вас есть помощник formateDate
(который преобразует формат даты в нечто более визуально привлекательное, например, «один месяц назад» или «29 июля 2013 года»). В этом случае, вы можете использовать запись в следующей форме: {{formateDate date}}
.
Компоненты? Помощники? Представления? ПОМОГИТЕ!
На Ember.js форуме вы можете найти ответы на интересующие вас вопросы, а StackOverflow обеспечивает поддержку, которая должна облегчить вашу головную боль.
Давайте приступим к созданию приложения.
В этом разделе мы попытаемся создать реальное приложение с простым интерфейсом для управления пользовательской группой (CRUD приложение). Вот что мы сделаем:
- рассмотрим архитектуру, которую мы стремимся получить;
- научимся работать с зависимостями, структурами файлов и т.д.;
- создадим модель с помощью Ember-DATA элемента
FixtureAdapter
; - рассмотрим, как маршруты, контроллеры, представления и шаблоны взаимодействуют друг с другом;
- наконец, заменим
FixtureAdapter
наLSAdapter
для сохранения данных в локальных хранилищах браузера.
Создание эскиза нашего приложения.
Нам нужно создать базовое представление для визуализации интерфейса пользовательской группы (смотри пункт 1 на изображении ниже). Нам нужно создать однопользовательское представление, чтобы иметь возможность увидеть свои данные (2). Нам нужно иметь возможность редактировать и удалять данные конкретно взятого пользователя (3). Наконец, нам нужен способ, благодаря которому мы смогли бы добавлять новых пользователей. Для этого мы будем повторно использовать форму редактирования.
Ember.js сильно зависит от принципа именования. Поэтому, если вы хотите создать /foo
(“нечто” – популярное имя для переменных, функций, временных файлов и их примеров в учебниках и руководствах; часто используется для обозначения текста, который вместо него должен подставить пользователь; иногда используется полная форма этого слова — foobar) страницу в своем приложении, вы должны придерживаться следующих обозначений:
foo
шаблон,FooRoute
,FooController
,- и
FooView
.
Подробнее о принципах Ember именования вы можете узнать в руководствах.
Что вам необходимо для того, чтобы приступить к работе.
Вам понадобится:
- jQuery,
- собственно сам Ember.js (что думаю вполне очевидно),
- Handlebars (т.е. Ember движок шаблона),
- Ember-Data (т.е. Ember слой персистентности (способность программного обеспечения создавать и поддерживать перманентные объекты) данных).
/* /index.html
*/
…
<script src="//code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="//builds.emberjs.com/handlebars-1.0.0.js"></script>
<script src="//builds.emberjs.com/tags/v1.1.2/ember.js"></script>
<script src="//builds.emberjs.com/tags/v1.0.0-beta.3/ember-data.js"></script>
<script>
// your code
</script>
</body>
</html>
Веб-сайт Ember имеет раздел сборки, где вы можете найти все необходимые ссылки для Ember.js и Ember-Data. В настоящее время Handlebars вы можете найти на официальном веб-сайте.
После того как мы загрузили все необходимые зависимости, мы можем приступить к созданию нашего приложения. Во-первых, мы создаем файл с именем app.js
, а затем мы инициализируем Ember:
/* /app.js
*/
window.App = Ember.Application.create();
Для того чтобы убедиться в правильности выполняемых действий, вы должны увидеть в консоли отладочный отчет Ember.
Структура нашего каталога файлов.
Существует не так уж много подходов в организации структур файлов и папок. Ember App Kit (Grunt ориентированная среда, которая представляет собой рабочую площадку для Ember приложений) представляет собой своего рода стандарт в организации. Этот стандарт был создан и поддерживается командой Ember. Вы могли бы разместить все элементы в одном app.js
файле. В конце концов, все зависит исключительно от ваших предпочтений.
В этом уроке мы просто поместим контроллеры в папку controller
, представления в папку view
и так далее.
components/
controllers/
helpers/
models/
routes/
templates/
views/
app.js
router.js
store.js
Нужно ли использовать шаблоны предварительной компиляции?
Есть два способа объявления шаблонов. Самый простой способ заключается в добавлении специальных script
тэгов в index.html
файл.
<script type="text/x-handlebars" id="templatename">
<div>I'm a template</div>
</script>
Каждый раз, когда вам потребуется новый шаблон, для него нужно будет добавить еще один тег. Вся эта процедура выполняется довольно быстро и легко, но может привести к появлению реального беспорядка, особенно если у вас слишком много шаблонов.
Другой способ заключается в создании .hbs
(или .handlebars
) файла для каждого из шаблонов. Он называется «шаблон предварительной компиляции». Далее в этой статье вы найдете отдельный раздел, посвященный этой теме.
В нашей нестилизированной демо-версии используются <script type="text/x-handlebars">
теги, а все шаблоны усовершенствованной демо-версии хранятся в .hbs
файлах, которые предварительно прокомпилированы с помощью Grunt задания. Таким образом, вы можете сравнить два подхода.
Настройка модели с помощью FixtureAdapter в Ember-Data.
Ember-Data – это библиотека, которая позволяет извлекать записи с сервера, держать их в Store
, обновлять в браузере и, наконец, сохранять их на сервере. Элемент Store
может быть настроен с помощью использования различных адаптеров (например, RESTAdapter
взаимодействует с JSON API, а LSAdapter
сохраняет ваши данные в локальном хранилище браузера). Далее в этой статье вы найдете отдельный раздел, посвященный Ember-Data.
Для нашего случая мы будем использовать FixtureAdapter
. Итак, давайте рассмотрим пример:
/* /store.js
*/
App.ApplicationAdapter = DS.FixtureAdapter;
В предыдущих версиях Ember, нужно было использовать подкласс DS.Store
. Теперь, чтобы создать экземпляр адаптера, нам не нужно его использовать.
FixtureAdapter
– это отличный способ начать работать с Ember.js и Ember-Data. У вас появляется возможность работать с образцами данных в стадии разработки. В конце концов, мы перейдем к LocalStorage адаптеру (или LSAdapter
).
Давайте объявим нашу модель. Пользователь будет иметь имя name
, адрес электронной почты email
, короткую биографию bio
, avatarUrl
и creationDate
.
/* /models/user.js
*/
App.User = DS.Model.extend({
name : DS.attr(),
email : DS.attr(),
bio : DS.attr(),
avatarUrl : DS.attr(),
creationDate : DS.attr()
});
Теперь, давайте наполним Store
образцами данных. Вы можете добавить столько пользователей, сколько вам нужно:
/* /models/user.js
*/
App.User.FIXTURES = [{
id: 1,
name: 'Sponge Bob',
email: 'bob@sponge.com',
bio: 'Lorem ispum dolor sit amet in voluptate fugiat nulla pariatur.',
avatarUrl: 'http://jkneb.github.io/ember-crud/assets/images/avatars/sb.jpg',
creationDate: 'Mon, 26 Aug 2013 20:23:43 GMT'
}, {
id: 2,
name: 'John David',
email: 'john@david.com',
bio: 'Lorem ispum dolor sit amet in voluptate fugiat nulla pariatur.',
avatarUrl: 'http://jkneb.github.io/ember-crud/assets/images/avatars/jk.jpg',
creationDate: 'Fri, 07 Aug 2013 10:10:10 GMT'
}
…
];
Подробную информацию о моделях смотрите в документации.
Демонстрационный пример создания маршрутизатора.
Давайте объявим Router
в соответствии с необходимым нам маршрутом (на основе схемы, которую мы сделали ранее).
/* /router.js
*/
App.Router.map(function(){
this.resource('users', function(){
this.resource('user', { path:'/:user_id' }, function(){
this.route('edit');
});
this.route('create');
});
});
Router
будет генерировать следующие результаты:
Единый указатель ресурсов (URL) | Имя Маршрута | Контроллер | Маршрут | Шаблон |
---|---|---|---|---|
N/A | N/A | ApplicationController |
ApplicationRoute |
application |
/ |
index |
IndexController |
IndexRoute |
index |
N/A | users |
UsersController |
UsersRoute |
users |
/users |
users.index |
UsersIndexController |
UsersIndexRoute |
users/index |
N/A | user |
UserController |
UserRoute |
user |
/users/:user_id |
user.index |
UserIndexController |
UserIndexRoute |
user/index |
/users/:user_id/edit |
user.edit |
UserEditController |
UserEditRoute |
user/edit |
/users/create |
users.create |
UsersCreateController |
UsersCreateRoute |
users/create |
Часть :user_id
называется динамичным сегментом поскольку соответствующий идентификатор пользователя будет выведен в URL. Таким образом, результат будет выглядеть как /users/3/edit
, где 3
– это идентификатор пользователя.
Вы можете объявить либо route
, либо resource
. Имейте в виду, что атрибут resource
представляет собой группу маршрутов и что он позволяет создавать вложенные маршрутизаторы.
resource
также сбрасывает вложенные именования до последнего имени ресурса. Это означает, что вместо UsersUserEditRoute
вы будете использовать UserEditRoute
. Другими словами, если вы использует ресурс, вложенный в другой ресурс, то ваши файлы будут именоваться следующим образом:
UserEditRoute
вместоUsersUserEditRoute
;UserEditControler
вместоUsersUserEditController
;UserEditView
вместоUsersUserEditView
;- Для шаблонов,
user/edit
вместоusers/user/edit
.
Подробнее о том, как объявить маршрут вы можете узнать из руководств.
Шаблон приложения.
Каждое Ember.js приложение нуждается в Application
шаблоне, с {{outlet}}
тегом, который содержит все другие шаблоны.
/* /templates/application.hbs
*/
<div class="main">
<h1>Hello World</h1>
{{outlet}}
</div>
Если вы решили следовать данному примеру и использовать шаблон без предварительной компиляции, то ваш index.html
должен выглядеть следующим образом:
/* /index.html
*/
…
<script type="text/x-handlebars" id="application">
<div class="main">
<h1>Hello World</h1>
{{outlet}}
</div>
</script>
<script src="dependencies.js"></script>
<script src="your-app.js"></script>
</body>
</html>
Пользовательский маршрут.
Этот маршрут связан с нашей группой пользователей. Вспомните о том, что мы видели ранее, в объявлениях. Маршрут – это способность адаптироваться к запросам модели. Маршруты содержат model
, через которую вы можете выполнять AJAX запросы (для получения модели, если вы не используете Ember-Data), или запросы к Store
(если вы используете Ember-Data). Если вы заинтересованы в получении моделей без использования Ember-Data, вы можете прейти к разделу, в котором я кратко объяснил, как это можно сделать.
Сейчас, давайте создадим UsersRoute
:
/* /routes/usersRoute.js
*/
App.UsersRoute = Ember.Route.extend({
model: function(){
return this.store.find('user');
}
});
Более подробную информацию о том, как определить маршрут model
вы можете найти руководствах.
Если вы посетите свое приложение через URL http://localhost/#/users
, ничего не произойдет, поскольку нам нужен users
шаблон. Он выглядит следующим образом:
/* /templates/users.hbs
*/
<ul class="users-listing">
{{#each user in controller}}
<li>{{user.name}}</li>
{{else}}
<li>no users… </li>
{{/each}}
</ul>
Цикл each
выполняет переборку каждого пользователя; в этом случае controller
равен UsersController
. Обратите внимание, что цикл {{#
each
}}
содержит оператор {{
else
}}
, поэтому, если модель не заполнена, то будет выведено сообщение
no
users
…
.
Поскольку мы следовали принципам Ember именования, мы можем опустить объявление UsersController
. Ember поймет, что используется совокупность, поскольку мы работаем с множеством пользователей.
Объектное управление в сравнении с массивом.
ObjectController
используется с одним объектом, а ArrayController
используется с несколькими объектами (например, с коллекцией). Немного ранее мы уже видели случай, когда можно не объявлять ArrayController
. Но в этом примере мы объявим его и, таким образом, можно будет выполнить сортировку свойств:
/* /controllers/usersController.js
*/
App.UsersController = Ember.ArrayController.extend({
sortProperties: ['name'],
sortAscending: true // false = descending
});
В этом случае мы просто отсортированы по алфавиту наших пользователей. Узнать больше о контроллерах вы можете из руководств.
Отображение количества пользователей.
Давайте использовать UsersController
для создания нашего первого обрабатываемого свойства. Оно будет отображать количество пользователей, поэтому мы сможем видеть изменения при добавлении или удалении пользователей.
В шаблоне нам просто нужно будет вставить следующий простой фрагмент:
/* /templates/users.hbs
*/
…
<div>Users: {{usersCount}}</div>
…
В UsersController
объявим usersCount
свойство — но это не совсем обычное свойство, поскольку оно будет возвращать длину модели.
/* /controllers/usersController.js
*/
App.UsersController = Em.ArrayController.extend({
…
usersCount: function(){
return this.get('model.length');
}.property('@each')
});
В основном, usersCount
использует метод .property('@each')
, который информирует Ember.js о том, что эта функция на самом деле является свойством, благодаря которому выполняется наблюдение за изменениями в одной из моделей коллекции (т.е. пользователей). Позже мы увидим, что значение usersCount
увеличивается или уменьшается, по мере того, как мы добавляем или удаляем пользователей.
Вычисленные свойства.
Вычисленные свойства – это достаточно мощный инструмент. Он позволяет вам объявлять функции как свойства. Давайте посмотрим, как всё это работает.
App.Person = Ember.Object.extend({
firstName: null,
lastName: null,
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}.property('firstName', 'lastName')
});
var ironMan = App.Person.create({
firstName: "Tony",
lastName: "Stark"
});
ironMan.get('fullName') // "Tony Stark"
В этом примере объект Person
имеет два статических свойства: firstName
и lastName
. Он также имеет вычисленное свойство fullName
, которое объединяет в полное имя значения из двух статических свойств. Обратите внимание, что метод.property('firstName', 'lastName')
указывает функции о необходимости повторного выполнения, если изменилось либо firsName
, либо lastName
.
Свойства (будь то статические или вычисленные) извлекаются с помощью .get('property')
и могут быть установлены с помощью .set('property', newValue)
.
Если вы уже установили для себя требуемую последовательность свойств, то лучше всего их объявлять с помощью одной функции .setProperties({})
, а не с помощью нескольких команд .set()
. Вместо того, чтобы выполнять объявление в форме…
this.set('propertyA', 'valueA');
this.set('propertyB', valueB);
this.set('propertyC', 0);
this.set('propertyD', false);
… вы можете сделать следующее:
this.setProperties({
'propertyA': 'valueA',
'propertyB': valueB,
'propertyC': 0,
'propertyD': false
});
В документации вы найдете гораздо больше информации о том, как связать данные с вычисленными свойствами, блоком наблюдения и компоновкой.
Перенаправление из классификационной страницы.
Если вы попытаетесь перейти на главную страницу своего приложения (http://localhost/
), то будете удивлены, почему же ничего не происходит. Все потому, что вы просматриваете классификационные страницы, и у нас нет index
шаблона. Давайте его добавим. Мы назовем этот шаблон index.hbs
.
Ember.js заметит, что вы создаете index
шаблон для IndexRoute
; поэтому дополнительная информация об индексе в Router
не требуется. Это называется первоначальным маршрутом. Доступны следующие три типа маршрутов: ApplicationRoute
, IndexRoute
и LoadingRoute
. Больше информации вы можете получить из руководств.
Теперь, давайте добавим ссылку на страницу пользователя через {{#link-to}}…{{/link-to}}
блок помощника. Почему блок помощника? Свое название он получил потому, что от вас требуется всего лишь написать текст между открывающим и закрывающим тегами, как если бы это был реальный пользовательский HTML элемент.
/* /templates/index.hbs
*/
{{#link-to "users"}} Go to the users page {{/link-to}}
В блоке отображается имя маршрута, к которому вы хотите перейти по ссылке, устанавливаемой в качестве первого аргумента (второй необязательный аргумент – это модель). На самом деле, это просто обычный <a>
элемент, хотя Ember также обрабатывает для нас имя класса active
при достижении подходящего маршрута. Использование функции link-to
идеально подходят для организации меню навигации. Больше информации вы можете получить в руководствах.
Другой подход заключается в использовании IndexRoute
для перенаправления на UsersRoute
. Опять же, все довольно легко сделать:
/* /routes/indexRoute.js
*/
App.IndexRoute = Ember.Route.extend({
redirect: function(){
this.transitionTo('users');
}
});
Сейчас, когда вы попытаетесь перейти на главную страницу, то будете немедленно перенаправлены на URL /#/users
.
Маршрут для одного пользователя.
Перед тем, как мы займемся созданием динамического сегмента, нам нужен способ, который бы позволил связаться с каждым пользователем из users
шаблона. Давайте для этой цели воспользуемся {{#link-to}}
блоком помощника внутри each
цикла.
/* /templates/users.hbs
*/
…
{{#each user in controller}}
<li>
{{#link-to "user" user}}
{{user.name}}
{{/link-to}}
</li>
{{/each}}
Второй аргумент из link-to
– это модель, которая будет передана в UserRoute
.
Итак, давайте вернемся к нашему пользовательскому шаблону. Выглядит он примерно следующим образом:
/* /templates/user.hbs
*/
<div class="user-profile">
<img {{bind-attr src="avatarUrl"}} alt="User's avatar" />
<h2>{{name}}</h2>
<span>{{email}}</span>
<p>{{bio}}</p>
<span>Created {{creationDate}}</span>
</div>
Обратите внимание, что вы не можете использовать <img src="{{avatarUrl}}">
, поскольку данные внутри атрибута связаны с bind-attr
помощником. Например, вы можете создать что-то вроде <img {{bind-attr height="imgHeight}}"/>
, где imgHeight
является вычисляемым свойством в текущем контроллере.
В руководствах вы найдете всю необходимую информацию об атрибутах и именах классов.
Пока все идет хорошо. Но когда вы нажимаете на пользовательскую ссылку ничего не происходит. Такая ситуация объясняется тем, что мы указали Router
, что UserRoute
должен быть вложенным в UsersRoute
. Итак, нам нужен {{outlet}}
, в котором будет визуализироваться пользовательский шаблон.
/* /templates/users.hbs
*/
…
{{#each user in controller}}
…
{{/each}}
{{outlet}}
{{outlet}}
представляет собой динамический заполнитель, в котором могут быть введены другие шаблоны при нажатии {{#link-to}}
тега. Это позволяет создавать вложенные представления.
Сейчас, у нас должна быть возможность просматривать, какой пользовательский шаблон вводится при посещении страницы по адресу /#/users/1
.
Погодите минутку! Мы же не объявляли ни UserRoute
, ни UserController
, но все работает! Почему так происходит? UserRoute
– это единственное число от UsersRoute
, поэтому Ember для нас сгенерировал маршрут и контроллер (в памяти). Слава Богу, для именования!
Чтобы не нарушать принципы согласованности выполним их объявление. Мы можем видеть, как они выглядят:
/* /routes/userRoute.js
*/
App.UserRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('user', params.user_id);
}
});
/* /controllers/userController.js
*/
App.UserController = Ember.ObjectController.extend();
Подробнее о динамических сегментах вы можете узнать из руководств.
Редактирование данных пользователя.
Шаблон для перехода к форме редактирования пользовательских данных будет выглядеть следующим образом:
/* /templates/user/edit.hbs
*/
<div class="user-edit">
<label>Choose user avatar</label>
{{input value=avatarUrl}}
<label>User name</label>
{{input value=name ...
Если вы хотите прочитать полностью статью, посетите сайт наших спонсоров