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, который демонстрирует это.

Надеюсь, что это будет полезно.