LAB NOTES

Working with computed array properties in Ember.js to build applications

Thadd SeldenWorking with computed array properties in Ember.js to build applications
Working with computed array properties in Ember.js to build applications
Thadd SeldenWorking with computed array properties in Ember.js to build applications
The Worry Free Labs development team loves Ember.js and one of the things we love about it is that it's opinionated on how your software should be be built. Unfortunately, that can also lead to some major frustration as you try to figure out "the Ember way" of doing things. One such problem came up this week and we wanted to share our solution.

The Problem

We're building an app that needs to dynamically update a list of service add-ons from an API as the user changes their selections. In the Ruby on Rails or other server-side tool, the list of of available add-ons would be easy to manage using view helpers, but because of how Ember handles caching of computed properties, you have to think about things differently. The following handlebars code shows what we're going for. [gist id=1abb0c8d270e7b278f3e] The problem occurs on line 6 since there's no way to do that in default Handlebars or Ember.

First Attempt: Custom Handlebars Helpers

If we were building this app in Rails, our first thought would be to write a custom helper to see if the current element is in the array of target elements. Based on that, we started looking in to how to build a custom Handlebars helper to perform the task and ended up with the following. [gist id=6e1b04b233b0452f4c9d] This actually worked perfectly, but had one major problem, it wasn't bound to the array properties so it didn't update when things changed. To make it bound, we'd need to use registerBoundHelper instead. Unfortunately, when we made that switch Ember got mad at us.
registerBoundHelper-generated helpers do not support use with Handlebars blocks
Sure enough, the docs say the same thing:
Bound helpers do not support use with Handlebars blocks or the addition of child views of any kind.
Time for Plan B.

Finding the Ember Way

We knew this couldn't be a unique problem but all of our Googling came back to the same answer: find a way to make a computed property that doesn't need an argument. We looked at the data model again and couldn't figure out where to add such a computed property. As we dug more, we realized we were missing one of Ember's key principles: the controllers are the models, but Ember Data just represents your APIs. Stepping up a tier from the raw data level, we started looking at how data was represented in the controllers and realized we could leverage an item controller to do the hard work. Lots of tinkering and trials finally brought us to a working solution: [gist id=8576d7e6b2d63cb22d7a] Now the buttons show and hide as the list of available add-ons changes, exactly the way we want it to. Unfortunately, our buttons don't work anymore. We originally defined the addAddOn action within the controller for the overall view (i.e. the controller mapped to the service itself). Since the action method is now being called within the scope block our new controller, we need to make a slight adjustment to get it working again. [gist id=d69af18a01bc5e9818d2] Also note that you don't have to use the {{#with}} approach here. You could just as easily set itemController on the each loop, but this is a slightly simplified version of our actual problem where that didn't work and I wanted to share the scoping approach.

Summary

Ember's approach can be a challenge sometimes and requires you to change the way you think about how to treat more complicated computed properties. It's also important to think about how to leverage your controllers to make your templates simpler.
Drop us a note
we're just an email away!
470-223-4370