I love Twitter Bootstrap: it’s a great framework for web front-ends and it has been a life safer ever since I downloaded the 1.0 version over a year ago. The power and acceleration it provides to web application development easily justifies why it is the most popular project on GitHub.

I recently stumbled upon Ember.js during a market study on JavaScript MVX frameworks. My company needed to build an AJAX front-end to one of our cloud services and I was trying to determine whether I should stick with the good old Backbone.js or go for something newer. (I’d actually met with Ember a while ago, back when it was called Sproutcore. I must admit that back then, I couldn’t really see the value in client-side MVC frameworks.

Eventually, I decided to go with Ember, despite the fact that it wasn’t entirely production-ready (today, most of the rough edges can actually be attributed to the Ember Data library).

I coded away for a couple of weeks until I decided it would make sense to add a few tooltips and popovers here and there. So I added the required attributes to the element and activated the two plugin via a jQuery selector. I ran the application and… surprise… it wasn’t working!

Popovers that won’t pop

I must have spent a good hour and half reading through the bootstrap doc, triple checking the code, debugging with Firebug. Nothing seemed wrong: all required libraries were included, the plugin activation ran as expected, the attributes were correctly placed… And then it hit me:

Damn, the stupid attributes are attached to elements which are located inside the Handlebar script! Obviously, what was I thinking: the jQuery selector won’t go and look inside the script tag…

Bottom line. If you have something like this in your app:

And you try to do this:

You can pretty much be sure that it won’t work…

You might still think that it would work because Handlebars scripts are eventually inserted into the DOM as HTML fragments and so the jQuery selection would work on them. The thing is, it’s all a matter of precedence: we’re running the selection before the templates are inserted and so the selection fails to find the elements.

I know some of you would be tempted to say at this point: ‘Dude, why are you blogging about trivial stuff?’ or ‘What a n00b!’. I agree this is a really simple and stupid thing, but I’m pretty sure others will make (or have already made) the same mistake. So read on for details about why it’s not working and how to fix it.

Why we can’t get any pop(corn)

As you can read in the documentation, Ember uses the Handlebars templating engine. A template in Handlebars can be specified between script tags so it’s delivered to a user’s browser and compiled on the client side. If you use Handlebars without Ember, you have to write the code instructing the browser to compile each template yourself (well, you could also pre-compile templates on the server, but that’s outside the scope of this blog post). However, if you use Handlebars with Ember, Ember will compile the templates for you. In short, when Ember is loaded, it scans the DOM for templates, automatically compiles them and assigns the compiled templates to the Ember.TEMPLATES map. This means that you can’t just register a handler to activate your Bootstrap tooltips and popovers after the DOM is loaded, because the Handlebars templates won’t have been compiled and inserted in the DOM yet. Duh!

(Aside: I like Ember’s approach and Handlebars is by far the best JavaScript templating engine I’ve come across so far, but it still feels somewhat “wrong” to have templates containing HTML inside script tags…).

(Tool)tips for safe popping

What are our options then?

One option is to simply avoid having markup for popovers or tooltips inside templates. That’s guaranteed to work, although it may not be convenient in some cases.

Another (suggested by a friend of mine) is to use setTimeout or setInterval to run the code activating popovers after a delay or periodically, but that’s just a quick and dirty workaround.

In my opinion, the best approach is to use the didInsertElement event of the application view and run the activation there:

Then, you can do this and it will work.

Bottom line

  • Never forget that HTML inside script tags is ignored by jQuery
  • Make sure you understand the basics about the inner workings of your client-side MVX framework
  • Always carefully read the documentation of the libraries you’re using
  • If you run into a nasty problem, Google is your friend… Hopefully some other bozo will have made the same mistake before 😉