Single Page App – Asynchronous Sample Using jQuery Promise to Render JSON Using Mustache

6327_image_58FAEDFAIn the previous posts on promises Promises for Asynchronous Operations Using jQuery, you learned how you can build promises using jQuery Deferreds and Promises. And in External Templates Using Mustache, jQuery, you learned how to bring in an external template.

It is time to show a real life example of how this code comes together. And in doing so, we have the beginning for a Single Page App.

In this code example, you will see how to use jQuery Promises to:

  • Load some JSON data
  • Load a Mustache template
  • Build your own deferred object for your own long-running function

Then when all three are accomplished, you’ll use the jQuery $.when() function to render the data.

For this example, you will need to have jQuery and Mustache loaded in your Scripts folder.Both are available on their Websites or from NuGet.

JSON File

Start with a file of JSON data named products2.txt in a Data folder.

Data/products2.txt


{
"products": [
{
"id": 1,
"name": "Toy1",
"category": "Toy",
"price": 45.05
},
{
"id": 2,
"name": "Toy2",
"category": "Toy",
"price": 35.20
}
]
}

Mustache Template file

Next, you’ll create the template productsList.mustache.html in a Templates folder.

Templates/productsList.mustache.html


Products:
<ul>
{{#products}}
<li>{{name}} {{category}} {{price}}</li>
{{/products}}
</ul>

HTML File

For simplicity in this demo, I place the script on the HTML page, although in actual practice, you would probably place it in an app.js file.


<!DOCTYPE html>
<html>
<head>
<title>jQuery loads External Mustache Template</title>
</head>
<body>
<h3>Default Header</h3>
<div id="products"></div>
<script src="Scripts/jquery-2.0.2.js"></script>
<script src="Scripts/mustache.js"></script>
<script>
var productsData, productHtml;
function loadJSON() {
var jsonPromise = $.getJSON(
'data/products2.txt', function (data) {
productsData = data;
console.log("loadJSON" + JSON.stringify(productsData));
});
return jsonPromise;
}
function loadTemplate() {
var templatePromise =
$.get('templates/productsList.mustache.html',
function (template) {
productHtml = template;
console.log("loadTemplate" + productHtml);
});
return templatePromise;
}
function doLongFunction() {
var deferred = $.Deferred();
setTimeout(function () {
deferred.resolve();
}, 2000);
return deferred.promise();
}
function renderTemplate(selector, template, data) {
var renderedHtml = Mustache.render(template, productsData);
$(selector).append(renderedHtml);
}
$(document).ready(function () {
$('#products').html('waiting…');
$.when(
loadJSON(),
loadTemplate(),
// add more data and templates as needed
doLongFunction()
)
.done(function () {
console.log("loaded");;
$('#products').html('');
renderTemplate('#products', productHtml, productsData);
// render each set of teamplates
})
.fail(function () {
console.log('I fire if one or more requests failed.');
});
});
</script>
</body>
</html>

Code Walkthrough

mustachelogoloadJSON function uses the jQuery.getJSON() function in the usual way. After setting data to the productsData variable, the function returns the promise that was returned from getJSON so that it could be used in $.when function.

loadTemplate function provides the same functionality, except putting the template into the productHtml variable and returning the promise returned from the jQuery.get() function.

doLongFunction shows how you can create you own Deferred object, which will use the resolve method to call all of the done handlers. It is best practice to keep the deferred object contained within its own function and not allow those outside to resolve or reject. We do that by returning the promise from the deferred object.

renderTemplate encapsulates the Mustache render function so it can be render by other data in templates at a selector elsewhere on the page.

$.when() takes the various functions that can run asynchronously. When each has been resolved, runs the done function or runs the fail function.

NOTE: The order of the execution of the functions inside the $.when() is undetermined. If you want to specify a chain, you can use the promise().then function, which will chain the functions in a particular order.

Sample Code

Sample code for this post is available in the DevDays repository on GitHub:  https://github.com/devdays/object-javascript/tree/master/Mustache

See 5a-MustacheExternalTempjQueryPromises.html

References

José F. Romaniello excellent article Understanding JQuery.Deferred and Promise includes some great samples and an excellent conceptual walkthrough