In 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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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
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.loadJSON
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