Simple External jQuery Templates - Part 2

In my last blog post I wrote about an interesting way to work with server side templates and avoid using callbacks to work with the elements you created. I worked on the concept some more and added some simple templating capabilities along with the ability to apply inline or external data. I'm posting this plugin to the jQuery website for downloading (along with parts of this blog post)

If you remember in the last post, the main problem was having to define callback methods to handle making changes to your jQuery object after it had been created. Instead, we used method forwarding and method queueing to allow direct access to the final object even before it had been created.

So instead of using callbacks your jQuery would look something like...

//loads an external resource but returns a placeholder to
//capture additional jQuery commands
$.template("/resource.html")
    .css({ color: "#f00" })
    .animate({ height: 400 })
    .click(function() { alert('clicked'); });

Interesting concept but requires some more work...

Important: This plugin simply helps avoid using callbacks to keep track of external templates.

What Is New?

The previous method worked pretty well if you're adding to a page but if you needed to replace something then you were back to using callbacks to handle removing content from the page. This version adds a couple extra new functions to work with the document after the template has finished loading

  • fill(selector): Empties the target and then fills the container with the current jQuery object. (accepts a string or a jQuery object as a selector)
  • replace(selector): Removes the target and then puts the current jQuery object in its place. (accepts a string or a jQuery object as a selector)
  • ready(delegate(element) { ... }): Simple way to perform any action that you want immediately following the external resources being loaded and processed.

All of these commands can be used along with the rest of the existing jQuery commands (like styles, animations, events, etc) because they follow the same queueing rules that the rest of the methods use. So for example, you could write the following command...

$.template("/resource.html")
    .ready(function() { $(document.body).css({ background: "#00f" }); })
    .fill("#placeholder")
    .fadeIn();

Templating Engine

Another thing that was missing from before was a quick, automated way to populate the template after it was loaded. This version introduces a simple engine that allows you to pass in an object or a URL to the source to JSON data you want to use and then populate the template automatically.

Here is a simple example of using a template with a data source...

template.html
<div class="customer-list">
  <a href="javascript:void(0);" class="refresh" >Refresh</a>
  <h2>%%title%%</h2>
  <p>%%description%%</p>
  <ul>
      <li each="%%customers%%" class="%%odd:'alt-row'%%" >
          <h4 class="%%first:'top-customer'%%" >%%name%%</h4>
          <ul>
              <li each="contacts" 
          class="%%first:'preferred'%% %%odd:'alt'%% contact-%%type%%">
          %%value%%
        </li>
          </ul>
          <hr if="%%!last%%" />
      </li>
  </ul>
</div>
data.json
{"title":"Customer List",
"description":"Customers and their contact methods.",
"customers":[
    { "name":"Mark", "contacts":[
        { "type":"email", "value":"mark@example.com" },
        { "type":"email", "value":"supermark@example.com" },
        { "type":"phone", "value":"555-1254" }
    ]},
    { "name":"Susan", "contacts":[
        { "type":"email", "value":"susan@example.com" },
        { "type":"phone", "value":"555-9811" }
    ]},
    { "name":"Jamie", "contacts":[
        { "type":"email", "value":"jamie@example.com" },
        { "type":"phone", "value":"555-4322" },
        { "type":"phone", "value":"555-1077" }
    ]}
]}
script.js
var list = $.template({
  template: "template.html",
  externalData: "data.json"
})
.ready(function() {
  $(document.body).css({ background: "#ffc" })
})
.appendTo("#target")
.find(".preferred")
  .css({ color: "#f00" })
  .end()
.find("h4")
  .css({ color: "#00f" });

The final rendered result would look like the following sample...

I suspect that a templating engine written in the duration it takes me to finish a Starbucks coffee isn't going to be high enough quality for everyone so you can easily replace it with a custom one by using the following command.

$.template(function(params) {
    /* perform formatting in this block (or send it to another templating engine)
     * params.html: The text provided by the template from the server
     * params.data: The JSON data provided for rendering (if any)
     */

    //must return a jQuery object
    return $(params.html);
});

This will replace the template formatting method for the duration of the page, however you can replace the formatting on a per request basis (but I'll explain that later)

How To Use

There are a few ways you can use the template command.

$.template(function(params) { ... });

Replaces the template formatting method with a custom method. The argument passed in contains a html property that contains the string of HTML to use for the template. The argument also contains a data property that contains the JSON data to populate the template with (if any). This should return a jQuery object when finished.

$.template("/path/to/template.html")

Simply downloads the HTML from an external path and then returns the jQuery object after it has finished loading. This option does not support templating.

$.template({ options })

Allows a lot more control over the request. The argument accepts the following properties.

  • template: The URL that points to the template file. You can optionally pass in an object that contains the same parameters as the $.ajax command so you can have full control over the request.
  • externalData [optional]: The URL that points to the JSON content for the template. You can optionally pass in an object that contains the same parameters as the $.ajax command so you can have full control over the request.
  • data [optional]: A JSON object with data to populate the template with.
  • complain [optional]: Determines if an exception should be thrown if the template and the data do not cooperate with each other (such as missing information).
  • error [optional]: A delegate that handles any connection errors. The first argument will tell where the error took place (external data or the template).
  • format [optional]: A delegate that performs formatting for a template. This won't replace the default formatting. Requires the same delegate type as the example for replacing the default version.

For now I'm simply uploading the code for downloading but I'm going to post it to the jQuery website shortly. I'd like to get some feedback and check for bugs before I save anything to the site.

January 24, 2010

Simple External jQuery Templates - Part 2

Second part of External jQuery Templates with improved code.

Downloads