Ember.js provides a complete structure for creating intricate client-side applications. It emphasizes “convention over configuration,” believing that most web applications share common development aspects best addressed with a standardized approach. However, identifying optimal abstractions and addressing all scenarios requires time and community input. The philosophy is to invest in perfecting core problem solutions and integrate them into the framework, rather than leaving developers to handle them individually.
Ember.js continually evolves to streamline development. However, like any advanced framework, it presents potential pitfalls for developers. This post aims to guide you around these challenges. Let’s dive in!
Common Mistake No. 1: Assuming the Model Hook Executes When All Context Objects Are Provided
Consider the following routes in our application:
| |
The band route includes a dynamic id segment. When the app loads with a URL like /bands/24, 24 is passed to the model hook of the band route. This hook deserializes the segment to generate an object (or object array) usable in the template:
| |
So far, so good. However, there are alternative ways to navigate routes besides loading from the browser’s navbar, such as using the link-to helper within templates. This snippet iterates through a band list and creates links to their respective band routes:
| |
The final argument for link-to, band, is an object populating the route’s dynamic segment, making its id the route’s id segment. The common misconception is that the model hook won’t be called in this case, as the model is already provided. While logical and potentially saving a server request, it’s not inherently obvious. A clever workaround involves passing the object’s id instead of the object itself:
| |

Ember’s Mitigation Strategy
Ember will soon introduce routable components, probably in version 2.1 or 2.2. Upon their arrival, the model hook will always be called, regardless of how a route with a dynamic segment is transitioned to. For more details, refer to the relevant RFC here.
Common Mistake No. 2: Overlooking the Singleton Nature of Route-driven Controllers
Ember.js routes define properties on controllers, acting as context for corresponding templates. These controllers are singletons, meaning their state persists even when inactive.
This is easily overlooked and can lead to unintended consequences. I stumbled into this, too. In my experience with a music catalog application, a songCreationStarted flag on the songs controller indicated song creation initiation for a specific band. However, switching to another band wouldn’t reset this flag, creating confusion as it appeared linked to the new band.
The solution involves manually resetting undesired persistent controller properties. One approach is utilizing the route’s setupController hook, called after the afterModel hook (which follows the model hook) on all transitions:
| |
Ember’s Mitigation Strategy
The arrival of routeable components will address this issue by eliminating controllers altogether. Routable components boast a more consistent lifecycle, being removed when transitioning away from their routes. This eliminates the aforementioned problem.
Common Mistake No. 3: Neglecting Default Implementation in setupController
Ember routes offer lifecycle hooks for defining application-specific behavior. We encountered model for fetching template data and setupController for setting up the template’s context, the controller.
setupController has a sensible default – assigning the model hook’s model as the controller’s model property:
| |
(context is the term used in the ember-routing package for what we refer to as model)
Overriding the setupController hook serves various purposes, such as resetting controller state (as in Common Mistake No. 2). However, forgetting to call the parent implementation from Ember.Route can lead to confusion, as the controller’s model property won’t be set. Always remember to call this._super(controller, model):
| |
Ember’s Mitigation Strategy
As previously mentioned, controllers, and with them, the setupController hook, are nearing their end, rendering this pitfall obsolete. However, the broader lesson is to be aware of ancestor implementations. The init function within Ember.Object, the foundation of all Ember objects, is another example to watch out for.
Common Mistake No. 4: Utilizing this.modelFor with Non-parent Routes
Ember’s router resolves models for each route segment as it processes the URL. Consider these routes:
| |
With a URL like /bands/24/songs, the model hooks of bands, bands.band, and bands.band.songs are called sequentially. The route API provides modelFor, allowing child routes to fetch models from parent routes, as they would have been resolved.
For instance, this code fetches the band object within the bands.band route:
| |
However, a common error is using a non-parent route name in modelFor. Modifying the previous example:
| |
Our method for fetching the URL’s designated band breaks, as the bands route is no longer a parent, and its model remains unresolved.
| |
The solution is restricting modelFor to parent routes and employing alternative methods, like fetching from the store, when it’s not applicable.
| |
Common Mistake No. 5: Misinterpreting Component Action Firing Context
Nested components have always posed challenges in Ember. While block parameters in Ember 1.10 has simplified things, determining the component on which an action fired from a child component will trigger can still be tricky.
Consider a band-list component containing band-list-items, allowing users to mark bands as favorites.
| |
The action name triggered on button click is passed to band-list-item and assigned to its faveAction property.
Let’s examine the band-list-item template and component definition:
| |
| |
Clicking “Fave this” triggers the faveBand action, which in turn fires the passed-in faveAction (setAsFavorite) on its parent component, band-list.
This trips up many, as they expect actions to fire like route-driven templates, on the controller and bubbling up through active routes. The lack of error messages, with the parent component silently absorbing the error, exacerbates the issue.
The rule of thumb is that actions fire on the current context. For non-component templates, it’s the current controller; for component templates, it’s the parent component (if any), or the current controller if not nested.
Therefore, in our example, band-list must re-fire the action received from band-list-item to bubble it up to the controller or route.
| |
If band-list resides within the bands template, the setFavoriteBand action needs handling in the bands controller, route, or one of its parent routes.
Ember’s Mitigation Strategy
This complexity increases with nesting levels (imagine a fav-button component within band-list-item). You’d essentially be tunneling through layers, defining names at each level (setAsFavorite, favoriteAction, faveAction, etc.).
“Improved Actions RFC”, available on the master branch and likely included in 1.13, simplifies this.
Our example becomes:
| |
| |
Common Mistake No. 6: Employing Array Properties as Dependent Keys
Ember’s computed properties rely on other properties, requiring explicit dependency definition. Consider an isAdmin property, true only if a role is admin:
| |
Here, isAdmin only updates when the roles array object changes, not when items are added or removed. A specific syntax addresses this:
| |
Common Mistake No. 7: Overlooking Observer-friendly Methods
Let’s expand our (now corrected) example from Common Mistake No. 6, creating a User class:
| |
Adding the admin role to a User leads to an unexpected outcome:
| |
The issue is that observers don’t fire (leaving computed properties unchanged) when standard JavaScript methods are used. While wider adoption of Object.observe in browsers might change this, we currently rely on Ember’s methods. Here, pushObject is the observer-friendly counterpart of push:
| |
Common Mistake No. 8: Mutating Passed-in Properties Within Components
Imagine a star-rating component displaying and allowing modification of an item’s rating, applicable to songs, books, or even a soccer player’s dribbling skill.
Template usage:
| |
Let’s assume it displays filled stars for each rating point and empty stars up to the maximum rating. Clicking a star triggers a set action on the controller, signaling a rating update. We could achieve this with:
| |
While functional, this approach has drawbacks. It assumes the item has a rating property, limiting its use for cases like Messi’s dribbling skill (potentially using score).
Secondly, it mutates the rating within the component, obscuring the source of property changes. Imagine another component in the same template using this rating, perhaps for calculating an average score.
“Data down, actions up” (DDAU) is key here. Data should flow downwards (route to controller to components), while components use actions to notify their context about data changes. How do we apply DDAU?
Let’s add an action name for rating updates:
| |
Now, use it to send the action upwards:
| |
Finally, the action is handled upstream (controller or route), updating the item’s rating:
| |
This change propagates down through the binding to star-rating, updating the displayed filled stars.
This way, mutation occurs outside components, and since only the action handling in the route is application-specific, component reusability remains intact.
The same component can be used for soccer skills:
| |
Final Thoughts
It’s crucial to note that many of these common mistakes will likely disappear or be significantly mitigated in Ember.js 2.x.
My suggestions address the remaining concerns, ensuring error-free development in Ember 2.x! For a PDF version of this article, head over to my blog and click the provided link.
About Me
Two years ago, I entered the front-end world through Ember.js, and it’s been an exciting journey. My enthusiasm led me to write extensively on my blog and guest posts, as well as speak at conferences. I even authored “Rock and Roll with Ember.js” for aspiring Ember developers. Download a sample chapter here.