I was thinking about latest @machty’s router changes in regard to loading states. This is a great step forward, but one thing bothers me a bit. We’re giving a lot of love to the scenario of loading routes with promises, but not a lot of love to a situation when for some reason I want to avoid using a promise.
The best example (which I also talk a lot about on most router related discussions, as you may have noticed) is a list of items and a detailed view. After thinking about approaching such a scenario, I would probably use a promise only for a detailed view, as this is the main thing to see, a list is just an addition, if it’s not loaded you don’t loose too much. That way, we can quickly render a list and move to fetching an individual view. A problem is, it usually involves a lot of boilerplate in templates, for example:
{{#if loading}}
List is loading
{{else}}
display list
{{/if}}
Additionally, if I would like to handle error properly, I would need to add extra logic for that.
In general there are 2 cases for rendering things, which are not a “main” view of the page (I’m being a bit simplistic here, but please bare with me):
- Without a nested UI, you may have a list, which will be rendered in the sidebar, but completely separately from the view, for example with
{{render "posts"}}
- With a nested UI, you may have a list, which is rendered in the sidebar, and the outlet for the main view. In such situation a list will be rendered alongside with a child template
Let’s start with a first case. When you render such a resource, you will most probably fetch actual records in the controller, maybe in a content computed property. If you want to handle errors, you will have to wire your own code, which will render an error template or a loading template while resource is loading. These steps may be easily abstracted and the templates can be rendered automatically if present.
In the second case, things are a bit more complicated, let’s take such a template as an example:
<ul class="posts">
{{#each post in controller}}
<li>{{post.title}}</li>
{{/each}}
</ul>
{{outlet}}
We can’t just swap the entire template for the time the list is loading, because it would also remove the outlet.
I think that the answer to both cases could be something like a {{resource}}
helper. In the first case, we could use it instead of render, like {{resource "posts"}}
, which would take care of creating a certain type of view and controller, which is able to deal with loading and error states. In the second case, we could use the same helper, instead of putting the posts list directly, but passing a block to it:
{{#resource "posts"}}
<ul class="posts">
{{#each post in controller}}
<li>{{post.title}}</li>
{{/each}}
</ul>
{{/resource}}
{{outlet}}
It would preserve the context of a parent controller, but just as with the first example, it would deal with loading and error states.
What do you think about that? I’m happy to implement this feature. I guess I will still implement it as an extension, but I would love to get it into core, because I feel that we lack a good abstractions in that regard.