Article summary
On my current project, I was tasked with implementing loading screens in our application. As it turns out, Ember has a built-in way of showing loading templates to the user! This built-in mechanism exists through what Ember calls substates. Let’s take a look at what these substates are and how you might use them.
Ember Substates: Loading and Error
Ember has two substates, one for loading and one for errors. It will transition into the loading substate if two things are true:
- The application is loading data via a promise during the
beforeModel
,model
, orafterModel
hooks of a route. - That promise does not return immediately.
On the other hand, Ember will transition into the error substate if:
- The application is loading data via a promise during the
beforeModel
,model
, orafterModel
hooks of a route. - That promise fails to load or throws an error.
When Ember applications are in a substate, they do not update the webpage’s URL. Applications stay in the error substate until the user navigates to a new page or a reload happens behind the scenes.
The loading substate exits automatically after a promise resolves. Ember will retry the original transition after exiting the loading substate.
Using Substates
Because Ember handles the transitions into and out of substates, using an Ember substate is as simple as defining a template for that state. In my application, this meant defining one template named loading.hbs
and another named error.hbs
.
In an application with nested routes, Ember will search for templates at each nested level in your application. This allows you to define different loading and error screens for different routes. The Ember guides have more information on how Ember loads templates for nested routes.
Helpful Tips
The first tip I have for using Ember substates is that when you’re creating a loading template, you need to make sure you have a corresponding error template. Initially, my application got stuck on the loading page if the promise failed to resolve. Once I added an error template, the application transitioned to the error template if a promise went unresolved.
My second tip is that /loading
and /error
are accessible directly. During development, I navigated directly to these routes so I could make tweaks to my template without simulating loading and error states. I’m not convinced that this is expected or desired behavior, so I wouldn’t be surprised if Ember removes access to these routes in the future. For the time being, it made development a bit easier for me.
Have you used Ember substates in your application? Let me know your best tips below!
Version Note: This post is based on Ember CLI version 3.5. Currently, Ember is on version 3.8.