Dispatches from the Edge: Template Views Part 2

written by Greg Moeck


In the last Dispatch we looked at how SproutCore incorporates the standard handlebars.js expressions and and helpers, and how bindings are automatically set for those expressions. This week, we’re going to take a look at some of the other ways that SproutCore extends handlebars.js to make interaction with the DOM even easier.

Class Bindings

A template needs to do more than tell the browser what content to display it also needs to tell the browser how to display that content. For example, in a to-dos application, we want our template to define what the to-do is, and if it has been completed, but we might also want to specify other aspects of the display. Maybe we want the text to grey out, or have a line through it once the to-do has been completed. How would we do this?

Well, with HTML we can modify the display using CSS. SproutCore has some helpers to make this easy. For example, If I wanted to have a class be added to an element only when a property is true I can use the classBinding helper. Let’s look at a concrete example.

Imagine that I have a template for to-do that looks like the following:

1
2
3
4
5
6
{{#view Todos.TodoItemView}}
<label>
<input class="check" type="checkbox">
{{ title }}
</label>
{{/view}}

Which I want to output something like:

1
2
3
4
5
6
  <div>
    <label>
      <input class="check" type="checkbox">
      Todo Title
    </label>
  </div>

What I would like to do is add a class to the div, so that if the to-do has been completed I can change the color of the text and put a line through it. So I add the classBinding helper into my view definition like this:

1
2
3
4
5
6
{{#view Todos.TodoItemView classBinding="isDone"}}
    <label>
      <input class="check" type="checkbox">
      {{ title }}
    </label>
  {{/view}}

What this will do is add the class “is-done” to the div when the isDone attribute is true of the view, and not add any class when it is not. The classBinding helper “dasherizes” the property when it is true, and adds that class to the div. So when isDone is true, the rendered HTML would look something like this:

1
2
3
4
5
6
  <div class="is-done">
    <label>
      <input class="check" type="checkbox">
      Todo Title
    </label>
  </div>

The classBinding helper is also available within the context of a collection instead of an individual view, only the syntax is a bit different. Since a collection renders an example view for each of its elements, instead of “classBinding“, I want to use “itemClassBinding.” It will, in a sense, apply the classBinding to each of the item views. So we take the same example that we have been using before and make it a collection, it would look like this:

1
2
3
4
5
6
  {{#collection Todos.TodoItemView itemClassBinding="content.isDone"}}
    <label>
      <input class="check" type="checkbox">
      {{content.title}}
    </label>
  {{/view}}

This would then render HTML that would look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  <ul>
    <li class="is-done">
      <label>
        <input class="check" type="checkbox">
        Completed Todo
      </label>
    </li>
    <li>
      <label>
        <input class="check" type="checkbox">
        Incomplete Todo
      </label>
    </li>
  </ul>

General Attribute Bindings

So thus far we’ve seen how SproutCore helps us create elements using mustache tagsand view helpers like #if; we’ve also seen how SproutCore helps us add or remove attributes to an element using classBinding. But there is one more way that it helps us describe our display. SproutCore also provides the bindAttr helper, that lets us modify attributes on an element.

When would we want to do this? Imagine if we wanted to display an image based on what item is currently selected in an application. Our template should contain an image tag that is bound to the selected item’s image and title. In order to do that, we would create a template that might look like the following:

1
2
3
4
  {{#view Application.ItemView class="item-display"}}
    <h1>{{item.title}}</h1>
    <img {{bindAttr src="item.url" title="item.title"}}>
  {{/view}

The rendered HTML from the template would then look something like this:

1
2
3
4
  <div class="item-display">
    <h1>Item 1</h1>
    <img src="link/to/item/1.jpg" title="Item 1">
  </div>

Then, if the selected item changes, the rendered HTML would be updated to be in sync with the selected item. The rendered HTML might then look something like this:

1
2
3
4
<div class="item-display">
    <h1>Item 2</h2>
   <img src="link/to/item/2.jpg" title="Item 2">
  </div>

Conclusion

Overall, it seems like the new template views have the ability to capture all types of DOM manipulation in a fairly simple form. If you’re curious to know what else they can do, or if you would like to see working code for all that it can do, I would recommend reading through the unit tests for the template view, which you can find here. The tests demonstrate all of the template view’s functionality, and overall do a good job documenting all of its features.

Until the next dispatch, this is Greg signing off.


Announcements:

We’re excited to welcome a Washington DC Meetup group to the family of SproutCore meetup groups! Check out their inaugural meeting tomorrow, April 20th!

Not in the DC area? There are also meetups coming up in these places:

Core Team Member Yehuda Katz will be speaking on Wednesday, 4/27 at Philadelphia’s Emerging Technologies for the Enterprise.

Hope to see you around! And, as always, let us know if there’s something you feel should be up here.