When building a web application, whether server- or client-rendered, it is pretty common to display a spinner for UI sections that might take some time to load.
Ember.js makes it pretty easy for us to achieve this: if you are fetching your data in your routes (as your should be) and returning promises from the
model hook, an intermediate route (named
loading) will be entered (and its template rendered) while the promise is resolved:
This substate is also available for nested routes: when
AppPostCommentsIndexRoute is fetching its model,
AppPostCommentsLoadingRoute will be entered and the template
post/comments/loading will be rendered.
While very useful, there's one frequent use-case not covered with those substates. What if there is several components in your interface, each backed by data coming from a different source? You will need to handle the spinners independently, and that is not something you can do with the route substates.
To the rescue,
Ember.PromiseProxyMixin! This mixin makes any subclasse of ObjectProxy, ObjectController or ArrayControllers promise-aware, according to the docs. When you include this mixin in one of your controllers, all you need to do is set a
promise property on it. Then, you can use various properties such as
isPending... If the promise succeeds, the
content property will be set. And if the promise rejects, the
reason property will be filled with the error.
Best part? It works with components too! Though the docs does not mention them, I have yet to encounter an issue when using this mixin in my components. See for yourself:
As you can see, pretty straightforward. Make sure you do not return a promise from your route, otherwise the
loading substate will be entered. One downside is that you cannot choose the name of the properties: you have to stick with
content, and the latter is not the most semantic of names. You can always make an alias of this is really an issue, though.
If you are using this mixin with controllers, one issue you will probably encounter is that wether your component is top-level (and linked to the route) or instantiated using
itemController, Ember will by default fill the
content property. In those cases, you will need to override
init in your controller, set
promise to the value of
content and clear
I hope this post was useful. If you have anything to add, please leave a comment or hit me up on twitter (@ksol) !