Client-Side Templating With Underscore

Objectives
Add the Underscore.js library to your projects
Create and compile an Underscore template
Use Underscore templating to display data from an array on your HTML page

What is a template?

  • A template is a document (or piece of code) that contains parameters that are dynamically replaced with data.

  • Thus far, we've been coding information (or data) directly into our HTML file. Eventually, the data on our HTML page will come from a server, and we'll need a way to dynamically display that data.

  • We'll use Underscore's templating engine to dynamically display data in our HTML, and the parameters will live inside <%= %> tags. We won't have data from a server yet, so for now, we'll store our data in an array.

Why use client-side templating?

  • Separate markup from logic. Remember this?

    $('#todo-list').append('<li class="todo">' + todo.name + ' - ' + todo.desc + '</li>');
    
    • When appending new HTML elements to the page, the string of elements to append will only get longer as you begin to write more complex markup.

    • Wouldn't it be nice if the HTML structure was already set up for us? That's where templating comes in!

  • Maximize code reusability and maintainability.

    • If you need to change your HTML structure for elements you're creating and displaying (e.g. adding an additional class name to your to-do tasks), all you have to do is change the template!

Underscore.js

Underscore.js is a JavaScript library that provides over 100 functions to help you manipulate and display data in JavaScript. Underscore also provides a templating engine, which we'll be using here.

A Note on Iterators

Among Underscore's 100+ helper functions are iterators that help us manipulate arrays. Perhaps most notably is the _.each iterator that loops through every element in an array and performs some action on it.

_.each takes in an array and a callback function as arguments. The callback function gives us access to the element we're at in the array and its index.

_.each([1, 2, 3], function (element, index) {
  console.log("index " + index + ": " + element)
});

_.each replaces our need for a for loop. The above code could be written like this if we weren't using _.each:

var arr = [1, 2, 3];
for (var i = 0; i < arr.length; i += 1) {
  console.log("index " + i + ": " + arr[i])
}

We'll be using _.each to iterate over the data we want to use in our template.

Setup

  1. Add the Underscore CDN to your index.html (remember you can go to cdnjs to search for CDN's). Make sure to require Underscore before your custom script file.

    <body>
     <div class="container">
       <!-- page content -->
     </div>
    
     <!-- jquery -->
     <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
    
     <!-- underscore -->
     <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
    
     <!-- custom script -->
     <script type="text/javascript" src="script.js"></script>
    
    </body>
    
  2. Next create the template below your custom script. Remember to give your template an id so we can use jQuery to select it (e.g. pets-template).

    <body>
     <!-- ... -->
    
     <!-- custom script -->
     <script type="text/javascript" src="script.js"></script>
    
     <!-- underscore template -->
     <script type="text/template" id="pets-template">
       <div class="pet">
         <p>
           <%= name %> - <%= species %>
         </p>
         <hr>
       </div>
     </script>
    </body>
    
  3. You will also need an element in your index.html where you will append the data from your template. Make sure to give this an id as well (e.g. pets-list).

    <body>
     <div class="container">
       <div class="row">
         <div class="col-md-6">
           <div id="pets-list"></div>
         </div>
       </div>
     </div>
    </body>
    
  4. Compile your template in your script.js. Calling _.template returns a function, which we save to the variable petsTemplate. We will later use our new petsTemplate function to pass in the data we want to render in the template.

    var petsTemplate = _.template($('#pets-template').html());
    
  5. Set up an array of test data in your script.js. Your object keys must match the parameters you set up in your template! (e.g. <%= name %> and <%= species %>) This array is our model, which we will use to store our data.

    var pets = [
     {name: "Sprinkles", species: "cat"},
     {name: "Bagel", species: "dog"},
     {name: "Fluffy", species: "dinosaur"}
    ];
    
  6. Iterate through your test data, using your template to create a new HTML element for each data object. Once the element is created, append it to the list element you set up in step 3 (e.g. pets-list). Note: We're also saving the object's index in the array to an HTML data attribute (this will come in handy when we want to delete elements from the DOM).

    _.each(pets, function (pet, index) {
     var $pet = $(petsTemplate(pet));
     $pet.attr('data-index', index);
     $petsList.append($pet);
    });
    

Challenges (& Tonight's Homework)

Refactor your To Do app to use Underscore templating. Feel free to make a copy of the To Do app solution if you want to start with fresh code. Follow the steps below and the code sample in this repo to guide your refactor.

Submit the link to your To Do app repo in the homework submission form.

Part 1

  1. Add the Underscore CDN to your To Do app. Make sure to require it before your custom script.

  2. Create an underscore template below your custom script. Remember to give it an id. Think about the data you will be displaying related to each to do item. That data will determine your template's parameters (inside the <%= %> tags).

  3. Set up a "list" element in your HTML where you will eventually append the data from your template. A <div> or a <ul> is a good choice. Remember to give it an id.

Part 2

  1. Compile your template, using jQuery to select it by its id.

  2. Set up test data in your custom script file. This should be an array of objects, where the keys match your template's parameters.

  3. Iterate through your test data, creating a new HTML element for each object in the array and appending it to the "list" element you set up in part 1 of the challenges.

Part 3

  1. Open your index.html in the browser to see if your test data displays on the page. If not, check the JS console to see what errors you're getting.

  2. Once you've successfully displayed your test data on the page, refactor your new To Do form to use the template when adding new tasks.

Part 4

Readings for tonight are from Mozilla Developer Network's Introduction to Object-Oriented JavaScript. Read these sections:

  • Object-oriented programming
  • Terminology
  • Prototype-based programming
  • JavaScript object oriented programming -- Custom Objects section

Stretch Challenges / Bonus

  1. When a new task is created, make sure you are pushing it into the array of "test" data you set up in part 2 of the challenges to keep your model updated with your view.

  2. Implement a delete functionality to remove tasks from your To Do list. Think about the places you'll need to make updates (Hint: model and view).

Docs & Reading