Idiomatic Emberjs для вложенных маршрутов, но не вложенные шаблоны
Это продолжение из Понимание маршрутов Ember.
Мастера/подробные представления великолепны, но я пытаюсь создать иерархический URL-адрес, не вставляя их шаблоны. Тем не менее, мне по-прежнему нужен доступ к родительской модели для таких вещей, как патчи и другие ссылки.
So /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
one, как и ожидалось. Но когда я нажимаю кнопку браузера, шаблон user
не будет отображаться снова. По-видимому, post post уничтожается, но родительский вид не вставлен повторно. Здесь есть несколько вопросов, которые упоминают об этом.
Затем я получил его для работы с чем-то вроде этого (метод # 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
и добавить его в качестве переменной ad-hoc в PostController
(это было бы необязательно, если маршруты были правильно вложены, и я мог просто установите свойство needs: 'user'
в PostController
). Кроме того, это может повлиять или не повлиять на внешний сервер в зависимости от реализации адаптера ember-данных или какой-либо другой технологии, используемой для извлечения данных с сервера (т.е. Это может вызвать ненужный второй вызов для загрузки 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
. Я хотел бы избавиться от этого последнего следа.
Ответы
Ответ 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, который демонстрирует это.
Надеюсь, что это будет полезно.