Hashrocket.com / blog

Bg default article large

Selleck: a jQuery Handlebars-like Templating System

posted on and written by Shane Riley in

Image 100x100 shane riley

Recently, I was working on a project that refreshed search results and their corresponding Google Map markers via Ajax and wanted to make it as easy to write the JSON data to HTML as possible. I initially thought to use Handlebars and write my HAML partials as part of the view, but thought that might be more than what I needed for our use, and since we're loading jQuery, jQuery UI, Google Maps and our search script, I wanted to try to keep the total amount of code added to the front end as small as possible. 10 lines of code later, I had my first version of Selleck parsing my JSON data and writing my HTML search results for me.

As a disclaimer, let me point out that Selleck isn't nearly as robust as Handlebars or Mustache (or underscore templates, etc.), but with all of the Hashrocket Javascript plugins, they are just enough to get the job done and give us the flexibility we want to make them useful in all of our projects.

On to the flashy bits! Here's how you'd use Selleck to transform a JSON object and HTML partial into a fleshed-out view. First, you write you HAML/HTML within a container that will show up on the page (or load it via Ajax!). Something like this will do the trick:

%script#tweet(type="text/selleck_tmpl")
    %article(id="{{id}}")
        %blockquote(cite="{{author}}")
            %p {{tweet}}
        %time(datetime="{{post_date}}") {{localized_post_date}}

Then you can take a tweet object like this:

var tweet = {
    id: "08486",
    author: "@shaneriley",
    post_date: "2012-03-30",
    localized_post_date: "Mar 30, 2012",
    tweet: "Waterfall Selleck sandwich!  http://vurl.me/QDSJ"
};

and write it to your page with jQuery like this:

$twitter_stream.html(selleck($("script#tweet").html(), tweet));

That's it. You've got HTML that has been filled in with the JSON data that was a much lighter request than your standard $.load or other typical get-HTML-via-Ajax request and much cleaner than what you'd have to write to fill a series of HTML elements with object properties.

Selleck will also process an array of JSON-like objects and create a completed HTML partial for each automatically. If our previous example were to look like this:

var tweets = [{
    id: "08486",
    author: "@shaneriley",
    post_date: "2012-03-30",
    localized_post_date: "Mar 30, 2012",
    tweet: "Waterfall Selleck sandwich!  http://vurl.me/QDSJ"
}, {
    id: "08487",
    author: "@shaneriley",
    post_date: "2012-03-30",
    localized_post_date: "Mar 30, 2012",
    tweet: "It's too bad Mustache May is no more."
}];

Selleck would iterate over each tweet and return one combined string of all the filled-in partials.

What about loops within a partial? Let's convert our tweet example to blog posts and add tagging. We may have 0 to n tags for each post, and rather than create another template for the tags and run Selleck on that collection afterwards, why not spit them out on first pass? Selleck's got you covered.

var posts = [{
    id: "08486",
    author: "@shaneriley",
    post_date: "2012-03-30",
    localized_post_date: "Mar 30, 2012",
    content: "Witty blog post goes here."
}, {
    id: "08487",
    author: "@shaneriley",
    post_date: "2012-03-30",
    localized_post_date: "Mar 30, 2012",
    content: "Kickball at 2 this Saturday!",
    tags: ["kickball", "weekend"]
}];
%script#post(type="text/selleck_tmpl")
    %article(id="{{id}}")
        %p {{content}}
        %footer
            %p
                by {{author}} on
                %time(datetime="{{post_date}}") {{localized_post_date}}
            %ul
                {{- tags.each do |tag|}}
                %li {{tag}}
                {{- end}}

Oh noes! Since there's no tags in the first post, we get an li with the text {{tag}} in it! That's embarrassing. Let's remove any empty elements while we're processing the template.

$blog.html(selleck($("script#post").html(), posts, { remove_empty_els: true }));

Yay! Now we're rocking nested loops and removing any elements whose content is nothing more than an empty template tag. Note that this option doesn't remove an element if it has a combination of plain and template text. In the near future, I hope to add if blocks that will allow you to conditionally remove or provide alternate content for missing properties. For now, remove_empty_els is the only option you can pass to Selleck.

And that's it! Now you no longer have to write those nasty Ajax callbacks that generate gobs of HTML in a place where it doesn't belong. Want to give it a try? Grab the code from GitHub and get to it!

Posted in Development and tagged with Javascript