The Emberist

Ember.js and Related Technologies

Learn More About Ember.js

{{bind}} and {{bindAttr}}

I've noticed recently that there's been some confusion about {{bind}} and {{bindAttr}} in Ember. Both of these helpers serve the same purpose, to bind properties into your templates, so why do we have two versions? To understand this a better, we need to know a bit about how {{bind}} works behind the scenes.

NOTE: {{bind}} is the default helper. If you do {{propName}} it's the same as doing {{bind propName}}. I'll refer to this as {{bind}} throught this post.

{{bind}} at Work

If you look at the source of your page with the WebKit Inspector or Firebug, you'll notice something unusual going on with {{bind}}: it's wrapped in <script> tags! So why do we do this? Well when a bound property updates, we need to know where in the DOM to make the changes. In the SproutCore 2 days, we tried wrapping things in <span> tags. This normally worked fine, except it was a pain to style. People didn't like us messing with their DOM. Furthermore, if you tried to put a binding inside of certain tags like <table> or <select> then things really went downhill.

Metamorph solves these problems by using <script> tags to mark the content so we know where to update. <script> tags are almost entirely transparent to the DOM1. They also are valid nearly everywhere in the document, including inside of <table> and <select> tags. For more information on Metamorph, see its README

But Why Won't It Work?

Imagine the results of using {{bind}} within a tag. If you try the following:

<a href="{{url}}">The Emberist</a>

You'll get something along the lines of:

<a href="
  <script id="metamorph-0-start" type="text/x-placeholder"></script>
  <script id="metamorph-0-end" type="text/x-placeholder">
">The Emberist</a>

This is clearly not valid DOM and it won't work.

This happens because Handlebars isn't context aware. It doesn't know that we are inside of a tag and attempts to output a <script> tag even though it isn't valid.

Enter {{bindAttr}}

{{bindAttr}} works by outputting a data-bindattr attribute in addition to the attribute that you specified. In the previous code, we would change to:

<a {{bindAttr href="url"}}>The Emberist</a>

This instead will output something along the lines of:

<a href="" data-bindattr-1="1">The Emberist</a>

Ember keeps an internal reference to the binding and, when the property changes, it looks for the tag with data-bindattr-1 and updates the specified attribute.

Now you have a better understanding of not just what you need to do to make things work, but why they actually work.

1. The only known problem in using <script> tags is that they do affect the CSS :first-child, :last-child, and :nth-child selectors. One solution is to use :first-of-type, :last-of-type, and :nth-of-type respectively, though this is not supported in all browsers.

blog comments powered by Disqus