Access Model in Ember View

Ember Views are used for event handling and creating reusable web components. To make them useful and interesting, model data needs to make it into and out of the view. Here is an example of how this works.

Define Your View

In our example, I'm making a simple dice rolling game. I want to use a view to represent the die on the screen and to handle the roll event. Your custom view must simply extend Ember.View in die-view.coffee:

App.DieView = Ember.View.extend
  templateName: 'die'

This is about the simplest view definition we could make. We'll make it a bit cooler later. For now, the view just knows where to get its markup. The die template can be any valid template. Ember, by default, uses Handlebars templates. I prefer Emblem templates, such as this die.emblem file:

li.die = die

This template will simply print the die object in an li with class of die. (There are an unusual number of 'die' references are in this example. This is for purely entertainment reasons, nothing more nefarious. :)

Render Data in Ember View Template

Next, you need to get your Ember View referenced in your template markup. In Emblem, to reference a view, start the line with a capital letter, specifically the name of your view. In this view, I list the dice in my game controller rolling array and render each die in the DieView in dice.emblem:

ul.dice
  each die in this.rolling
    App.DieView

Using this code, the parent template dice.emblem passes the die variable to the DieView, where its child template, die.emblem renders die data.

Pass Data Into Ember View

To pass the die data from dice.emblem into the DieView to be used programatically, however, you need an extra attribute. Change dice.emblem, adding contentBinding:

ul.dice
  each die in this.rolling
    App.DieView contentBinding="die"

Now you can access the die data via a special Ember View variable named content. Why might you want to get to this data programatically in the view code?...

Passing Data from Ember View to Controller

You might want to pass it somewhere else. Remember, Ember Views are meant to take primitive UI events and translate them into semantic events, meaningful to your application. For example, our view might want to translate a die element click on the DOM into a roll event in the application. We made the modification to dice.emblem to pass the data in. Now, let's send it to the controller like this:

App.DieView = Ember.View.extend
  templateName: 'die'

  click: (evt) ->
    @get('controller').send 'roll', @get 'content'

We retrieve the content variable (holding the die), and send it to the controller in scope as a roll event. The controller now must implement a roll function. Let's say we have a game controller. That code might look like this in game-ctrl.coffee:

App.GameController = Ember.ObjectController.extend

  roll: (die) ->
    # roll die and advance game accordingly

If the controller doesn't implement this function, the current Ember Route may implement it in its events object. If neither the controller or the route implement it, an exception is thrown.

In this way, Ember Views show their worth in collecting events and translating them to meaningful verbs that we can act upon in our application. They become reusable, allowing us to bind different content to them on different occassions. Do Ember Views help you in this way? Is there a better way?