JavaScript Templating – Kind of Like ItemRenderers or Binding from Flex

One of the things I’ve been struggling with on the HTML/JS app I’ve been working on is how to get binding-like functionality. It seems like there are a few ways to do it, but the ones I looked at didn’t seem to fit with the general pattern of JavaScript and I wanted something a bit more elegant. Luckily, I just didn’t know what to look for, and once I came across templates, I realized I had found exactly what I wanted. Templates in JavaScript act like ItemRenderers but in my example I was able to use them to create a page, and then dynamically change the data on that page almost like I would if I were binding an object to a form in Flex.

And that’s almost exactly what templating lets you do. Here’s my example. I’m creating a list of beers, and when I click on one of those beers, I want to load a bunch of information about that beer in a form so I can make changes to it and save those changes to my database. With Flex Mobile I was able to do that pretty robustly because I can pass data between views very easily and bind elements in the second view to my data. With jQuery mobile, there’s nothing quite that fancy, so I had to rely on templates.

It turns out there are a ton of JavaScript templating libraries out there. Underscore.js includes a templating feature and looks interesting but I tried Mustache.js off the bat and found it pretty simple to use.

I started off with the template itself. In my case, it was a basic form that I called beer_detail.mustache

    <form action="#" method="post">
<div id="beername" data-role="fieldcontain">
            <span id="beerlabel">{{ beername }}</span>
            </div>
        <div id="brewername">{{ brewername }}</div>
        <div id="brewerlocation">{{ brewerlocation }}</div>
        <div id="beerstyle">{{ beerstyle }}</div>
<hr>
        <div id="quantity" data-role="fieldcontain">
<label for="quantityslider">Quantity: {{quantity}} </label>
<input type="range" name="quantityslider" id="quantityslider" value="{{ quantity }}" min="0" max="25"  />
</div>
        <div id="purchasedate" data-role="fieldcontain">
        <label for="purchasedatefield">Purchase Date:</label>
                <input type="date" name="purchasedatefield" id="purchasedatefield" value="{{ purchasedate }}"  />
</div>
        <div id="price" data-role="fieldcontain"><input type="text" value="{{ price }}"></div>
        <div id="cellardate" data-role="fieldcontain">
        <input type="date" name="cellarfield" id="cellardatefield" value="{{ cellardate }}"  />
</div>
        <div id="cellartemp">Cellar Temperature: {{ cellarTemperature }}</div>
        <div id="brewdate" data-role="fieldcontain">
        <input type="date" name="brewdatefield" id="brewdatefield" value="{{ brewdate }}"  />
        </div>
<a href="#pintley">This beer on Pintely</a>
        <button type="submit" data-theme="a">Submit</button>
        </form>

The double brackets {{ }} are all of the variable names that the template looks for so those will be replaced with actual data when the template gets rendered. I liked the similarity to Flex’s binding syntax.

One of the things you can do in jQuery Mobile is pass url variables, so for the first part of my application, I use a list of the beer names with a link to a page named beer_details.html that includes an id parameter that I use to look up the beer. In this example I’m using a Lawnchair database called “beers” and just calling the all() method to get all of the beers in the database. Then I iterate through those and build the list.

 
     beers.all(function(arrBeers){
          for(var i = 0; i<arrBeers.length;i++)
          {
               console.log(arrBeers.length);
               var listdiv = document.createElement('li');
                 listdiv.setAttribute('id','listdiv');
                 listdiv.innerHTML = '<a href="beer_details.html?id='+arrBeers[i].key+'">'+arrBeers[i].value.beername+'</a>';              
               $('#beer_list').append(listdiv);    
          }
          $('#beer_list').listview("refresh");
     });

The beer_details.html page itself just contains some skeleton code for jQuery mobile. The code will inject the template into the div id="content" tag. This way, all of the jQuery functionality stays with the application so it can use the back button, has the header/footer, etc and plays the transitions back and forth. So it’s pretty bare bones:

<div data-role="page" id="beerdetail" style="type-inline">
     <div data-role="header">
          <h1>Your Beers</h1>
     </div>
     <div id="content" data-role="content" align="center">
 
     </div>
     <div data-role="footer" data-id="foo1" data-position="fixed">
          <div data-role="navbar">
               <ul>
                    <li><a href="beers.html">Beers</a></li>
                    <li><a href="styles.html">Styles</a></li>
                    <li><a href="scan.html">Scan Barcode</a></li>
                    <li><a href="locations.html">Locations</a></li>                   
               </ul>
          </div>
     </div>
</div>

So now that the structure is set up, we can use Mustache to populate our template with data and inject the resulting HTML into the DOM. The first step is to set up the data object. In this code I parse the URL to figure out the ID of the beer, then use Lawnchair to retrieve that data. I’m listening for the pagebeforeshow method, but I’m not sure if that’s the best one. But it allowed me to get the data and change the DOM before the page showed, which is important for being able to render the template.

     $('#beerdetail').live('pagebeforeshow',function(e) {
          var beerID;
          beerData = {};
 
 
          var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');    
 
          for(var i = 0; i < hashes.length; i++)
          {
            hash = hashes[i].split('=');
            if(hash[0] == "id")
            {
                 beerID = hash[1];
            }
          }                 
 
     });

Once I have the beerID, I can use LawnChair to grab the information. Then I can use that object and pass it to Mustache to build the template. The Mustache library uses a .to_html() method that takes a reference to the template and the object that holds the data, in this case beerData. In the example below, there’s a bit of chaining going on. First I have to get the data, then when that is returned, it calls a function that will go out and load my .mustache template using Ajax, and finally, when that page is retrieved, I call Mustache.to_html() to get the HTML and then inject that HTML into the content so it will render correctly. This code goes inside the pagebeforeshow event handler.

          beers.get(beerID,function(obj){
               beerData = obj.value;
               $.get('templates/beer_detail.mustache',
                    function(data){
                         template = data;    
                         var renderedhtml = Mustache.to_html( template,beerData);
                         $("#content").html(renderedhtml);    
                    });
          });

And voila! Now when we click on a beer from the list, the data gets inserted into the template and when we move back and forth the data will update as we click on new beers.

This is much, much easier than trying to go through the DOM and insert/modify the form variables and also lets us potentially use different templates depending on the beer I choose. So far I’ve found templates to be helpful for getting around concepts like binding in HTML/JS.

I’ve gone ahead and put this project up on GitHub. It’s kind of a disaster at this point, since it’s basically my learning project, but you can see how this was done.

Related posts:

  1. Using Lawnchair for Data Storage in PhoneGap
  2. Beer List for Flash Camp 2011
  3. Talking to Chris Brichford about HTML and JavaScript in AIR
  4. WebSocket Charting Demo with HTML5 and JavaScript
  5. RoboHelp Lives! (And it’s kind of cool too)
  • http://pradeek.com Pradeek

    You might want to check out KnockoutJS http://knockoutjs.com/ 

  • jlawmi

    If you are still looking for binding checkout knockout.js, or backbone.js perhaps

  • http://blog.digitalbackcountry.com Ryan Stewart

    Does backbone.js run on top of underscore.js? I’ll definitely check out knockout. My goal is to get to the point where I’m using backbone.js for a lot but wanted to try a few different approaches so I would appreciate what backbone.js solves.

    =Ryan

  • http://ludicast.com Nate Kidwell

    I have been using angularjs for a flex-alike framework. Similar yet different, but a lot of fun.

    The team did a comparison version to the peepcode backbone app. It was like a third the code in angularjs thanks to databinding.

    The closest thing I have to Flex, plus can use it with Coffeescript and Haml.

  • http://ludicast.com Nate Kidwell

    It relies on underscore for some stuff. The templating is underscore by default, but can be replaced though.

  • Julien Castelain

    Hi Ryan,

    Backbone.js does require Underscore.js as a dependency as it uses most of Underscore’s functions internally, Knockout.js is also quite nice, but I really like the Backbone’s features, the fact it’s data driven, actually, it feels ‘kind of’ like the stuff I’ve done in Flex minus the components. I definetly recommend also checking Google Closure or Spine.js, it has templates and more :) Concerning ‘Binding’ in JS I think Knockout is closer than Backbone.js to what you’ve been doing in Flex. 

  • Julien Castelain

    mostly everything in backbone uses underscore, not only templates but also core components, model, collections, etc…

  • Anonymous

    I’ve been using backbone.js, it has good tutorials and some modules that make it more powerful.

    I don’t know if I’d call it “Flex-Like”, but it definitely lets you organize your code in a sane manner, which is the problem with most javascript apps.

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • Guest

    Curious have you found a spark like “List” in HTML/JS that can accept item-renderers/templates, and support large number(1000) items?

  • J S

    As an Actionscript developer it took one week to learn Javascript & JQuery. One week. The syntax is supper similar.

    though come now and develop an App, thats a whole different story. Extend a List, Listen for the Mouse, etc, things like these get way too complicated… finding the right JS stack is even more complicated.

    I really look forward to an HTML5+JS Solid & proven framework like how Flex is today, but a “Standard”, which at first you’d think means, works across all browsers. But not even.

    I guess we’ll have to wait for it to mature more.

  • DAVE

     JavaScript is so complicated,

  • http://twitter.com/corbanb corban baxter

    We’ve been doing lots with backbone and underscore for templates its a great workflow. Backbone gives you a great API for data models so you can easily access data, sort it and works great with underscore too. There is much more to backbone than meets the eye. I’d highly reco it for any dev wanting to build JS apps small or big.

  • http://blog.digitalbackcountry.com Ryan Stewart

    Sweet, and good to know. Backbone seems to be a big winner all around. What kind of stuff are you building with it? Anything you can share? And feel free to email me – ryan@adobe.com