Getting Started with EmberJS

Posted on

Tomster: The EmberJS Mascot

I was posed with a very free-form project after I got my feet wet in the Ibotta Ruby on Rails codebase. The task: create a kick-ass Single-Page Application to replace the minimal Rails front-end website. It needed to communicate with the existing RoR API and needed to be released within a few months.

Choosing a Framework

I had worked briefly with Backbone and Marionette, but I wanted to research Angular and Ember before going with what I already sort-of knew.

There have been a lot of posts on the tubes lately talking about how to choose a framework. I suggest you read them and, perhaps, take my opinion with a grain of salt. So why did we choose to go with Ember? Well, honestly, we chose Ember because we really didn’t have a lot of experience in writing a large single-page app. Ember is an opinionated framework and, since we didn’t already have an opinion, we borrowed theirs.

EmberJS

Overall, I’m really happy with day-to-day development in Ember. Once you get the hang of the key concepts, you can iterate really quickly and don’t have to write much boilerplate to get basic functionality out the door. Ember’s opinionated nature can be restrictive, especially when Ember Data comes into play. I’ll describe Ember Data separately and dedicate this post to common ‘gotchas’ I experienced in the Ember core project over the last few months.

Key Concepts

I would recommend starting off by closely reading the EmberJS guides. This will help you to get a basic idea of what Ember is all about and how to start writing basic code. However, there are a few things that took me a little while to wrap my head around.

Handlebars is Dumb

Like really, dumb. When I first got started, I was trying to place way too much logic into my Handlebars templates. This is what your associated Ember controllers and components do for you. If you’re starting off writing a Handlebars helper, you’re probably doing it wrong.

For instance, consider iterating over an array of objects and doing something with every 10 items. Originally, I thought to attack this in Handlebars, maybe like this (pseudocode):

{{! each 10 items}}
{{#each obj in array}}
  <div>
    {{obj.name}}
  </div>
{{/each}}

No dice. Remember: Handlebars is dumb. It is not meant to do any manipulation of your data. It only displays what you’ve already created. A better way to do this is with an Ember Mixin. Something like this:

App.ItemGrouper = Ember.Mixin.create
  itemGroups: ( ->
    arr = []
    i = 0
    @get('itemsToGroup').forEach (item) =>
      if i %% @get('numPerGroup') == 0
        arr.push([item])
      else
        arr[arr.length - 1].push(item)
      i++
    arr
  ).property 'itemsToGroup.@each'

Then, in your Handlebars template, iterate over what you just created with your ItemGrouper.

{{#each group in itemGroups}}
  <div class='group-container'>
    {{#each item in group}}
      <div class='item'>
        {{item.name}}
      </div>
    {{/each}}
  </div>
{{/each}}

With this approach, Handlebars is allowed to be dumb and just handle displaying the work you did in Ember.

Remember, if you’re trying to do anything computational in Handlebars, you’re doing it wrong. Do your manipulation in Ember and expose it to Handlebars for display.

Ember Computed Properties Don’t Trigger

I’d frequently be exploring an implementation, place a debugger statement in a new computed property and never see it get fired. It took a while for me to remember that computed properties aren’t executed unless something is requesting its value. This is actually a really good thing, since Ember is trying to save cycles not computing unused properties.

However, sometimes you need to see what’s happening before using the new property. Luckily, there’s an easy way to test this while you’re developing. For instance, consider a computed property, fullName that’s computed based on variables firstName and lastName. In production, you’d want something like this:

fullName: (->
  firstName + lastName
).property 'firstName', 'lastName'

But if no one in your app is @geting fullName, this logic will never fire. You can work around this by utilizing the observes keyword. So, in development, you could change the block above to:

fullName: (->
  debugger
  firstName + lastName
).observes('firstName', 'lastName').on('init')

Now you’ll actually this your debugger statement when firstName or lastName is initialized. You’ll likely not want to leave this in production, but it’s a good, quick way to make your computed property fire for testing.

Observes on('init') and on('change')

This one is easy to figure out once you actually discover them, but they’re not well documented. When you create an observer, you can use .on('init') or .on('change') to help define the behavior of your observer. .on('init') will always fire each time the property is set, even if the value did not change. .on('change') will fire only when the property is @set to a new value. For instance, consider the following:

foo: false

fooObserver: (->
  firstName + lastName
).observes('foo').on('change')

... elsewhere ...
@set('foo', false)

In this, fooObserver will not fire because the value did not change. This caused a few subtle bugs in my code because the value wasn’t changing. The options to fix the problem would be to initialize foo to null so that the observer would fire when the value is first set, or to utilize .on('init') which will fire every time the value changes, and when it initializes.

It’s a New(er), Rapidly Changing Framework

Keep in mind that Ember is a pretty new framework. A lot of the posts on StackOverflow and on forums are incorrect due to their age. Make sure you take a look at when posts/answers were submitted before taking their solutions as valid. In my experience, if they were written before ~August 2013, they could be wrong. EmberJS 1.0 was released on August 31st, 2013, and lots changed in the pre-release versions.

Keep in mind that the community is here to help! I’ve frequently used the EmberJS IRC room (#emberjs on freenode.net) to get help. It’s a great resource in addition to the normal resources, like StackOverflow and the EmberJS discussion board.

More to Come!

Overall, I really enjoy working in EmberJS and would recommend playing around with it if you’re trying to choose a SPA Framework. In the coming weeks I’ll be posting on other things I’ve learned while working with Ember, Node, Express, Brunch, CoffeeScript, Karma, Mocha, Chai and Sinon. Stay tuned!

Find an issue?
Open a pull request against my blog on GitHub.
Ben Limmer