Static Class Notation in bindAttr: why :some-class not .some-class


#1

You specificy a static class in the bindAttr helper using a colon, i.e.

{{bindAttr class=":a-static-class aDynamicAttr"}}

Any reason not to use a period instead, as in:

{{bindAttr class=".a-static-class aDynamicAttr"}}

Seems closer to what we’re used to.


#2

when I see that code I see as a symbol, like in ruby.

Perhaps the creators of Ember JS took their inspiration from Ruby. Just a guess.

Symbols are one of the more amazing and actually quite useful programming language constructs, IMHO.

Too bad Javascript doesn’t have the the equivalent.

http://glu.ttono.us/articles/2005/08/19/understanding-ruby-symbols

For a good example of the importance of symbols

http://www.robertsosinski.com/2009/01/11/the-difference-between-ruby-symbols-and-strings/


#3

You got me curious so I started digging a little deeper. I am not a core member so this is just my interepretation.

From the API docs

http://emberjs.com/api/classes/Ember.Handlebars.helpers.html#method_bindAttr

A hard-coded value can be used by prepending : to the desired class name: :class-name-to-always-apply.

<img {{bindAttr class=":class-name-to-always-apply"}}>

Results in the following rendered output:

<img class="class-name-to-always-apply">

You see a similar colon pattern with Dynamic Segments in the router.

Note :post_id

App.Router.map(function() {
  this.resource('posts');
  this.resource('post', { path: '/post/:post_id' });
});

Since these are processed values that are converted to actual strings in the DOM, the designers probably decided to implement a consistent pattern to identify strings and make sure they are safe before being output to the DOM.

Here are some relevant code snippets from the source to see what is happening when the bindAttr class binding is processed.

github.com/emberjs/ember.js/blob/master/packages/ember-handlebars/lib/helpers/binding.js

  // Handle classes differently, as we can bind multiple classes
  var classBindings = attrs['class'];
  if (classBindings != null) {
    var classResults = EmberHandlebars.bindClasses(this, classBindings, view, dataId, options);

    ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"');
    delete attrs['class'];
  }

Note the call to

Handlebars.Utils.escapeExpression

If we look at handlebars source

we find

  escapeExpression: function(string) {
    // don't escape SafeStrings, since they're already safe
    if (string instanceof Handlebars.SafeString) {
      return string.toString();
    } else if (string == null || string === false) {
      return "";
    }

    // Force a string conversion as this will be done by the append regardless and
    // the regex test will do this transparently behind the scenes, causing issues if
    // an object's to string has escaped characters in it.
    string = string.toString();

    if(!possible.test(string)) { return string; }
    return string.replace(badChars, escapeChar);
  },

By force escaping the strings Ember and handlebars increase the security and prevent some exploit vectors.

Rails does something similar.

Because the string has a colon next to it, I think that indicates that it is treated as a special kind of entity and it is parsed and passed back to the DOM in a known safe way.


#4

To me it is just sugar around the syntax booleanProperty:class-if-true. When you always want the class, you just omit the boolean property, and it becomes :class-always-here.


#5

I agree with @belluzj. It’s just intuitive and consistent as a colon without anything prefixing it.