Error Substates in Ember


The aspect of loading states and error states are recognized as 'substates' in Ember. It's a nifty little feature in the Router which developers should definitely be using more often.

Where does it all exist? So at it's most basic, a webpage shows you data it retrieved from some server. You click on a link it takes you to another page and loads different data. In Ember this transition happens with the model hooks: beforeModel(), model(), afterModel(). This transition, the loading and rendering of the data - takes some time. A lot of things can happen during this time: too many requests get fired, you get an error from your API, or your user gets bored.

Ember provides a nice UI touch by introducing loading and error substates.

From the Ember Guides:
"The Ember Router allows you to provide feedback that a route is loading, as well as when an error occurs in loading a route."

Pretty much. Feedback is good. Especially for errors.

One really cool and simple way to start loading your error states, is by generating a template called error.hbs. That's it. Ember will identify and use this template when it detects any HTTP error message.

(Ember Guides uses loading and error events. I can't say if that is the suggested way to do it.)
This post doesn't cover error events, or use any actions that rely on link-to or transition-to. We can accomplish the same using templates and routes.

Setting it Up

Given a file structure which has an application.hbs, you're going to be creating an application-error.js (route) and application-error.hbs (template). Depending on how complicated the logic you're going to use, you can get away with just a template for simpler error messages. Since we're using Ember CLI, file generation will be handled quite smoothly.

Note: We can just as easily name these files as error.js & error.hbs and Ember will respond likewise. When you start having multiple error substates then it's best to be as explicit as possible.

In your error.hbs, go ahead and write:
This is an error message

Turn off your wifi, and reload your Ember app. You should now see your custom error message! You didn't even need to change anything in the router. We didn't even need the application-error.js route file.

The Setup Controller

This is where your route file comes in. The setupController() hook modifies the Controller behavior for the actions you want to make with the model hook, then it goes and restores the default controller behavior (if you use _super). It takes two params: the controller, and the model.

Custom Error Messages

Regular error message codes such as 404, 503s and 502s are easy from the client to detect and respond to. But what if you are relying on data from an API and you want to give custom error messages if the response data isn't quite correct. For example: your API loads an empty sheet. While this is technically not an error (response: 200, status OK), you may want to tell your users that a misconfigured or empty sheet is an error.

For this, using some simple logic you can now expand the scope of your error substates to become active and give custom error messages from the server.

The solution I found was not really to implement any new logic in the error route, but the main application's route before the transition takes place. So application.js route instead of application-error.js route. In short: the solution implemented ended up being to throw a new error for any misconfigurations. For the example just mentioned the code logic would look like:

if (!Ember.isArray(columns) || columns.length === 0) { throw new Error('This sheet is misconfigured.'); }

The final template logic ended up being quite simple at the end of it.


{{#if parsedMessage}}

Server: {{parsedMessage}}


Server Message: {{notFoundMsg}}


Status Code: {{message.status}}


Another nice feature I discovered in Ember was the ability to load a message for something we can call- an empty state. This is when no data is returned. Typically you would have seen an {{#each}} block that would iterate through the model and display the results out in a list format. Well in your application template also consider adding an {{else}} conditional within the {{#each}} for empty states.


  • Wanted to have a custom error page for Bad Gateway errors (your 502s and 503s). Sounds simple, disconnect the wifi and I should see the error page. However, since I was using a microservices API that spoke to a legacy codebase, just the mere act of running a local server always meant that I would get a 200 status. Bit of a pain to test it out. The short answer is that the change had to be made at the API level. But the logic at the app level remained consistent. I also heard you can use Dev Chrome tools to help out in such cases.

  • URLs changed. Not really an issue, but good to know. So when transitioning from the main application page to a sheet_:id page, I expected the url to show the sheet id. But since we stopped the transition midway from the model hook, it prevents the sheet data from being loaded.

  • There are plenty of edge cases that can come about, as I figured out. Sometimes your server may not have messages to display or have it in a weird output format (for which you should be setting default messages). Internet Explorer had some issues with displaying the results as well.

Resources that helped me: