I am trying to figure out what the best practice is for loading nested resources in Ember. I thought I had this figured out, but there are a few cases that aren’t completely documented or discussed elsewhere.
Consider a simple Blog which has 2 resources Posts and Comments. The relationships are,
- Post hasMany Comments
- Comment belongsTo Post
The UI design is typical of a Blog, it needs to,
- show a list of Posts with links to each Post.
- show each Post with it’s comments below.
- lazy load and show comments of each post after displaying the Post body.
The desired URLs are,
- /posts - list of posts
- /post/:id - each individual post
From what I can tell, The standard approach to these scenarios is to have,
- PostsRoute - load list of posts via
model
, render intoposts
template - PostRoute - load post for id via
model
, render intopost
template
So far so good. Now to render the comments into the post template. There are 2 approaches.
- {{render ‘comments’ post}} - use the render helper in the post template
- renderTemplate - call render(‘comments’, options) with an outlet, etc.
Both approaches generate a controller for the resource and that controller is used by the comments template to lookup bindings to display.
This CommentsController
will use needs
and postBinding
to lookup the post that it is referring to.
But how do you load the comments for the individual post when on
/post/1
? There is no route used by the rendered Comments, so themodel()
hooks are out.
I haven’t been able to answer this satisfactorily so far. My solutions to this are,
- Add a load() method to the CommentsController.
- Then load the comments for that post manually, called in
init()
directly or deferred.
- Make
Comment
a nested resource ofPost
.
- change
/posts
links to/post/1/comments
, instead of/post/1
. - load the comments in the
setupController
ofPostRoute
Solution 2 somewhat works. But isn’t really a solution at all, because a real world scenario would require rendering multiple such resources. And you can’t switch to N sub resource routes simultaneously.
Solution 1 works to an extent. However the same controller is used for different posts. So you end up having to figure out the post for whom the comments were rendered. And load the comments if they don’t match. Further there is no easy way to know when post model behind it is switched out when the route changes. ie:- comments once loaded show for subsequent posts. The enter
and exit
hooks are on the Route not the controller.
I have recently discovered the {{control}}
helper, where the controller isn’t shared. But given the experimental warnings, I am reluctant to use it, if it could be removed. Also it isn’t really a solution, the actual loading still needs to be done.
The reason I am looking for a canonical solution to this, is that this pattern repeats consistently across nearly every UI design.
For instance, When a User is on a parent resource, the UI needs to either show top 10 type lists, aggregates, or stats of the child resources.
I am quite new to Ember, so please let me know if I am missing some key Ember idea that makes it possible to do this.
I especially like the async Router style hooks, which are declarative. Instead of loading a resource you tell Ember that a resource needs to be loaded.
I welcome any suggestions on how to go about building this, even if it isn’t currently feasible within core.
Thanks.