Идиоматические Emberjs для вложенных маршрутов, но не вложенных шаблонов
Это продолжение маршрута "Понимание Эмбер".
Основные / подробные представления великолепны, но я пытаюсь создать иерархический URL-маршрут без вложения их шаблонов. Однако мне все еще нужен доступ к родительской модели для таких вещей, как ссылки на крошки и другие ссылки.
Так /users/1/posts
должен отобразить список сообщений для пользователя 1. И /users/1/posts/1
должен отображать пост 1 для пользователя 1, но он не должен отображаться внутри user
шаблона {{outlet}}
, Вместо этого он должен полностью заменить 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
определение ресурса, но если я возьму его, Эмбер не найдет users
маршрут. Я хотел бы избавиться от этого последнего остатка.
1 ответ
Вы можете определить родительский шаблон, чтобы он просто отображал точку и имел индексный маршрут, который будет отображаться внутри него. Тогда для вложенного ресурса вы можете сделать то же самое.
<script type="text/x-handlebars" data-template-name="user">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="user/index">
<h2>user/index</h2>
</script>
<script type="text/x-handlebars" data-template-name="posts">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="posts/index">
<h2>posts/index</h2>
</script>
Таким образом, это не будет мастер / деталь.
Маршрутизатор будет:
App.Router.map(function() {
this.resource('user', function() {
this.resource('posts', function() { });
});
});
Тогда, если вам нужно получить информацию о родителе, вы можете использовать modelFor
, Так что, если бы вы были в сообщениях, вы могли бы сделать this.modelFor('user')
;
Вот jsbin, который демонстрирует это.
Надеюсь, это полезно.