Это продолжение статьи Понимание маршрутов Ember.
Основные/детальные представления великолепны, но я пытаюсь создать иерархический URL-маршрут без вложения их шаблонов. Однако мне по-прежнему нужен доступ к родительской модели для таких вещей, как навигационные ссылки и другие ссылки.
Таким образом, /users/1/posts
должен отображать список сообщений для пользователя 1. А /users/1/posts/1
должен отображать сообщение 1 для пользователя 1, но оно не должно отображаться внутри {{outlet}}
шаблона user
. Вместо этого он должен полностью заменить шаблон user
. Однако мне по-прежнему нужен доступ к текущему пользователю в шаблоне post
, чтобы я мог вернуться к пользователю, показать имя пользователя и т. д.
Сначала я попробовал что-то вроде этого (метод № 1):
App.Router.map(function() {
this.resource('user', { path: '/users/:user_id' }, function() {
this.resource('posts', function() {
this.resource('post', { path: '/:post_id' });
});
});
});
...
App.PostRoute = Ember.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
},
renderTemplate: function() {
this.render('post', {
into: 'application'
});
}
});
Это заменило шаблон user
на post
, как и ожидалось. Но когда я нажимаю кнопку «Назад» в браузере, шаблон user
больше не отображается. По-видимому, представление сообщения уничтожается, но родительское представление не вставляется повторно. Здесь есть несколько вопросов, в которых упоминается это.
Затем я заставил его работать с чем-то вроде этого (метод № 2):
App.Router.map(function() {
this.resource('user', { path: '/users/:user_id' }, function() {
this.resource('posts');
this.resource('post', { path: '/users/:user_id/posts' }, function() {
this.resource('post.index', { path: '/:post_id' });
});
});
...
App.PostRoute = Ember.Route.extend({
model: function(params) {
return App.User.find(params.user_id);
},
setupController: function(controller, model) {
controller.set('user', model);
}
});
App.VideoIndexRoute = Ember.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
}
});
App.PostIndexController = Ember.ObjectController.extend({
needs: 'post'
});
Но мне это кажется немного хакерским и не очень СУХИМ.
Во-первых, мне нужно снова получить User
в PostRoute
и добавить его как специальную переменную в PostController
(в этом не было бы необходимости, если бы маршруты были правильно вложены, и я мог бы просто установить свойство needs: 'user'
в PostController
). Кроме того, это может повлиять или не повлиять на серверную часть в зависимости от реализации адаптера ember-data или какой-либо технологии, используемой для извлечения данных с сервера (т. е. это может привести к ненужному второму вызову для загрузки User
) .
Мне также нужно дополнительное объявление `PostIndexController' только для того, чтобы добавить эту новую зависимость, что не имеет большого значения.
Еще одна вещь, которая кажется неправильной, это то, что /users/:user_id/posts
появляется дважды в конфигурации маршрутизатора (один вложенный, один нет).
Я могу справиться с этими проблемами, и это работает, но я думаю, что в целом это кажется вынужденным и не таким изящным. Мне интересно, не хватает ли мне какой-то очевидной конфигурации, которая позволит мне делать это с обычными вложенными маршрутами, или если у кого-то есть рекомендация для более "способа Ember.js" сделать это.
Я должен упомянуть, что, несмотря на технические достоинства метода № 2, мне потребовалось довольно много времени, чтобы понять, как заставить его работать. Потребовалось много поисков, чтения, экспериментов, отладки и т. д., чтобы найти правильную комбинацию определений маршрутов. Я полагаю, что это не очень уникальный вариант использования, и пользователю должно быть очень просто настроить что-то подобное, не тратя часы на пробы и ошибки. Я буду рад написать несколько советов по этому поводу в документации Ember.js, если это окажется правильным подходом.
Обновлять:
Спасибо @spullen за разъяснение этого. Мой случай был не таким простым, как в примере, потому что для некоторых подмаршрутов нужны вложенные шаблоны, а для некоторых нет, но ответ помог мне разобраться. Моя окончательная реализация выглядит примерно так:
App.Router.map(function() {
this.resource('users', { path: '/users/:user_id' }, function() {
this.resource('users.index', { path: '' }, function() {
this.resource('posts')
});
this.resource('post', { path: '/posts/:post_id' }, function() {
this.resource('comments', function() {
this.resource('comment', { path: '/:comment_id' });
});
});
});
});
Итак, теперь posts
отображается под шаблоном users
, но post
заменяет все. Затем comments
отображается под post
, а comment
, в свою очередь, под comments
.
Все они являются подмаршрутами users
, поэтому пользовательская модель доступна для всех из них без акробатики, выполняя this.modelFor('users')
в каждом маршруте, где это необходимо.
Итак, шаблоны выглядят так:
users
|- posts
post
|- comments
|-comment
Я не знаю, зачем { path: '' }
нужен для определения ресурса users.index
, но если я уберу его, Ember не найдет маршрут users
. Я хотел бы избавиться от этого последнего пережитка.