Real Basic Tutorials: Underscore.js

So someone once told me that a web page I had made looked like it was “from the 1980’s school of web design.”

“There wasn’t a web in the 80’s,” I said.

“That’s my point.”

OK, it hurt, but looking at the page I had to admit she was right. It wouldn’t have been pulled out of the GeoCities archive for mocking or anything, but there were probably lots of pages that looked like it in there.

Since then, I’d stuck with tinkering with WordPress themes, but after the lovely wife came up with a couple website ideas, I’ve revisited HTML and learned a bit of programming (and then a different bit of programming as I realized the first plan wasn’t the best one, and then more as the technology changed underneath me….) One of the frustrations I’ve run into is that a lot of stuff assumes a level of skill that isn’t quite there yet for me; I’m at that point where I can look at examples and follow along, even spot errors in production code, but when I try to write something from scratch, I stare at the editor screen, with no real idea of where to start. It feels like the difference between being able to read a language, or flip through a phrasebook without too many embarrassing pronunciation errors, and actually being able to speak it.

So while I could see that a given library was going to be useful for a project, when I actually went to make something, I was usually left with a few sample code snippets and an API reference. That’s enough for someone who can already speak the language, but I wanted something that would show not just how to use it, but why you had to do things a certain way. And for most things, I couldn’t find that sort of tutorial. So I figured I’d write them, since I was going to have to bang my head against the code anyway, and maybe save somebody some trouble down the line. Please note that I’m going to assume that you have a basic understanding of HTML5 and javascript for these tutorials. This one also assumes that you know how to use jQuery to select elements and get or update their content.

First up: the javascript template engine Underscore. OK, Underscore isn’t just a template system; it has a lot of utility functions, most of which are fairly straightforward. But I’m going to be using it as the template engine for Backbone, and Backbone depends on Underscore anyway.

Now, Underscore being yet another javascript library, setup is very easy; you just add it to the head element in a script tag:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Blank Template</title>
    <meta charset="utf-8">
    <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script>
  </head>
  <body>
    I got no body.
  </body>
</html>

Now you can use any of Underscore’s functions in your page. (Note that for these examples, I’m getting the scripts from cdnjs.com, a wonderful little service that hosts a lot of javascript libraries on the CloudFlare network, for free!) Of course, for the template functions, you’ll almost certainly want to use jQuery as well, to make selecting elements and manipulating the page easy.

Like jQuery, Underscore lets you abbreviate the library name with a single character, to cut down on typing. Anybody want to guess what character that is? (If I ever write a javascript library, I’m going to call it Backspace.) So the isEmpty function looks like this:

_.isEmpty({});
=> true

Simple enough, right? Most of Underscore’s functions are equally straightforward, and there’s a lot of useful stuff in there—things that you could do yourself with a few lines of code, or a few dozen, but Underscore gives them to you as function calls, so you can concentrate on getting your logic right and not on reinventing and retesting the wheel.

Templates are a bit trickier. Here’s an imaginary user profile that you might see on a site that does all the processing on the server.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>staticUserProfile Example</title>
    <meta charset="utf-8">
    <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script>
  </head>
  <body>
    <h1>Bob's Profile</h1>
    <h3>Name: Bob Robertson</h3>
    <h3>Address: 1010 Some Street, New York, NY, 10001</h3>
    <h3>Phone: (212) 555-1212</h3>
    <p>Interests: Bob likes apples, big ones and floating ones.</p>
  </body>
</html>

Click here to see a rendered version of the page.

Now, a server based application would grab the information from a database and do all the processing itself, and then pass the final HTML down to the client. But maybe you need to reduce the work done by your server, or are building a webapp where you want users to be able to access APIs on multiple servers without having to fetch all that information yourself? In that case, you need to be able to format the results directly on the client machine. So what if you just needed a page that looked like this:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>User Profile Page</title>
    <meta charset="utf-8">
    <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script>
  </head>
  <body>
    <h1><%= header %></h1>
    <h3>Name: <%= name %></h3>
    <h3>Address: <%= address %></h3>
    <h3>Phone: <%= phone %></h3>
    <p>Interests: <%= interests =></p>
  </body>
</html>

Click here to see a rendered version of the page.

Of course, if you clicked on the code above, you know it’s not quite that simple—you have to retrieve the data, and then have Underscore format it. But working code isn’t much more complex.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>User Profile Page</title>
    <meta charset="utf-8">
    <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.0/jquery-1.8.0.min.js "></script>
    <script>
      window.onload = initPage;
      function initPage() {
        // Declare all the variables.
        var exampleValues = {},
          parsedTemplate = "",
          // Get the template from the script block.
          templateText = $('#profileTemplate').html(),
          // Then we use Underscore's template function to compile it 
          // into a stand alone function that we can feed values to and 
          // get HTML output.
          demoTemplate = _.template(templateText);
        // Here, we grab the data, and put the results into exampleValues. 
        // I'm using .ajax instead of .getJSON so I can set 'async: false' 
        // for the demo; in production you'd be checking for async calls 
        // to return, but I wanted to keep the script simple.
        $.ajax({url: "data/profiledata.json", async: false, dataType: "json", success: function(json) {exampleValues = json;}});
        // Finally, we call the demoTemplate function we created earlier, 
        // passing in the data we just retrieved, and then put the  
        // resulting HTML into the empty div.
        parsedTemplate = demoTemplate(exampleValues);
        $("#profileBlock").html(parsedTemplate);
      }
    </script>
  </head>
  <body>
    <div id="profileBlock"></div>
    <!-- Wrap the template in a script tag with type="text/template". 
      Since the browser doesn't recognize that type, it won't render 
      or process it, but will leave it for jQuery to grab the content -->
    <script id="profileTemplate" type="text/template">
      <h1><%= header %></h1>
      <h3>Name: <%= name %></h3>
      <h3>Address: <%= address %></h3>
      <h3>Phone: <%= phone %></h3>
      <p>Interests: <%= interests %></p>
    </script>
  </body>
</html>

Click here to see a rendered version of the page.

If you ignore the comments, that page is just 15 lines longer than the static example.

The actual template is in a script block at the bottom of the page. By giving it a type of “text/template” the browser ignores the script contents and doesn’t render it or try to process it (though I did have a problem where javascript comments inside the script block weren’t being recognized and appeared on the page.) But jQuery sees it as just another piece of the DOM, and grabs the contents of the element when we call templateText = $('#profileTemplate').html().

Most of the work is done when we create the demoTemplate object by calling demoTemplate = _.template(templateText). (In fact, this is the only time we call Underscore directly in the whole example.) We pass the contents of the #profileTemplate script block into Underscore’s template function. Any HTML or text is left alone. The <%= %> tags tell Underscore to insert a value there from the parameters passed to demoTemplate when it’s called. You could also use <%- %> to have the values be automatically HTML-escaped, if it hasn’t been already. Finally, <% %> tags allow you to pass in javascript; the entire template could also be written as <% print('<h1>' + header + '</h1><h3>' + … %>.

Then you pass the JSON data to demoTemplate to get HTML, and use jQuery to insert it on the page.

Strictly speaking, you don’t have to create a template object; you can just pass the data directly into the _.template function call along with the template structure, and get HTML out immediately. But I think the template object is easier for debugging, and for dealing with loops or page updates.

Of course we’re only creating one profile at the moment. Lets try to display multiple profiles, say for a company directory.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Staff Profile Page</title>
    <meta charset="utf-8">
    <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.0/jquery-1.8.0.min.js "></script>
    <script>
      window.onload = initPage;
      function initPage() {
        // This code is unchanged, except we're getting a different JSON file.
        var exampleValues = {},
          parsedTemplate = "",
          templateText = $('#profileTemplate').html(),
          demoTemplate = _.template(templateText);
        $.ajax({url: "data/multiprofiledata.json", async: false, dataType: "json", success: function(json) {exampleValues = json;}});
        // The for loop runs the values for each employee through the 
        // demoTemplate function, and builds the parsedTemplate HTML 
        // from the results.
        for (employee in exampleValues.company_employees) {
          parsedTemplate += demoTemplate(exampleValues.company_employees[employee]);
        }
        // The rest of the page is the same as the previous example.
        $("#profileBlock").html(parsedTemplate);
      }
    </script>
  </head>
  <body>
    <div id="profileBlock"></div>
    <script id="profileTemplate" type="text/template">
      <h1><%= header %></h1>
      <h3>Name: <%= name %></h3>
      <h3>Address: <%= address %></h3>
      <h3>Phone: <%= phone %></h3>
      <p>Interests: <%= interests %></p>
    </script>
  </body>
</html>

Click here to see a rendered version of the page

So now you should see the profiles of all four members of my imaginary company. From here, it would be simple to add a stylesheet and styling to the page, or to display only one profile at a time but add next and previous buttons so you could page through the results, or to pull your data from a remote API instead of a local JSON file.

So that’s the basics of Underscore templates! If you’d like to grab my example code and play with it, you can download it from GitHub. I hope this was helpful. If you’ve got any questions or feedback, please leave a comment! Now to go beat my head against Node. Why did I think a project where I’d have to write a server would be a good idea, anyway?

Note: Some of the content in this tutorial was modified from the Underscore.js API documentation. Thanks to DocumentCloud and all the Underscore.js community for their work on the project!

2 Comments

  1. Please send me json structure to get better idea of this example.My email id is mayank.mittal.cool@gmail.com

  2. Sorry for the delay, been neglecting the blog again. I for some reason didn’t link to the json document you’d use for this, but the structure for this particular example is pretty simple:

    {
    “header”: “Bob’s Profile”,
    “name”: “Bob Robertson”,
    “address”: “1010 Some Street, New York, NY, 10001”,
    “phone”: “(212) 555-1212”,
    “interests”: “Bob likes apples, big ones and floating ones.”
    }

Leave a Reply

© 2017 Joe Helfrich

Theme by Anders NorénUp ↑