Quick JsRender Tutorial

This is a quick walkthrough of JsRender. JsRender is the next-generation jQuery Templates, optimized for fast, string-based rendering. We will be using jQuery in our examples below, but JsRender is not dependent on jQuery.

We start with the HTML below. Please download JsRender and make it available on your local environment. In our example, jsrender.js is in the root folder.

	<!DOCTYPE html>
	<html>
	<head>
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
		<script src="jsrender.js" type="text/javascript"></script>
		<script type="text/javascript">
			var movies = [
				{ name: "Up", releaseYear: "2009", languages: [{ name: "English" }, { name: "Spanish" }] },
				{ name: "Finding Nemo", releaseYear: "2003", languages: [] },
				{ name: "Toy Story", releaseYear: "1995", languages: [{ name: "English" }, { name: "German" }] }
			];
		</script>
	</head>
	<body>
		<ul id="movieList" />
	</body>
	</html>

Everything is standard HTML, JavaScript and JSON so far. Now let’s start using JsRender. After the movieList, let’s insert the the template.

<script id="movieTemplate" type="text/x-jsrender">
		<li>
			{{>name}} {{>releaseYear}}
		</li>
</script>

Notice we insert data by using the syntax {{>variable}}.

After that, insert the call to JsRender template render.

<script type="text/javascript">
		$("#movieList").html(
			$("#movieTemplate").render(movies)
		);
</script>

What our code does is it calls JsRender to go through the array of movies and create the HTML for each movie using the template provided. Running the HTML in the browser outputs.

  • Up 2009
  • Finding Nemo 2003
  • Toy Story 1995

The complete code looks like

	<!DOCTYPE html>
	<html>
	<head>
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
		<script src="jsrender.js" type="text/javascript"></script>
		<script type="text/javascript">
			var movies = [
				{ name: "Up", releaseYear: "2009", languages: [{ name: "English" }, { name: "Spanish" }] },
				{ name: "Finding Nemo", releaseYear: "2003", languages: [] },
				{ name: "Toy Story", releaseYear: "1995", languages: [{ name: "English" }, { name: "German" }] }
			];
		</script>
	</head>
	<body>
		<ul id="movieList" />

		<script id="movieTemplate" type="text/x-jsrender">
			<li>
				{{>name}} {{>releaseYear}}
			</li>
		</script>

		<script type="text/javascript">
			$("#movieList").html(
				$("#movieTemplate").render(movies)
			);
		</script>
	</body>
	</html>

Now let’s go over some basic JsRender syntax.

1. If you want to print values without HTML encoding, use {{:value}}.

	{{:name}} {{>releaseYear}}

2. If you want a default value, use ||.

	{{>name}} {{>releaseYear || 'N/A'}}

3. If you want to display the current index during a loop, use #index.

	{{:#index+1}} {{>name}} {{>releaseYear}}

4. If you want conditions, use {{if}} and {{else}}.

	{{if releaseYear == '1995'}}
		{{>name}} {{>releaseYear}} (Classic)
	{{else releaseYear == '2009'}}
		{{>name}} {{>releaseYear}} (New)
	{{else}}
		{{>name}} {{>releaseYear}}
	{{/if}}

5. If you want loops, use {{for}}

	{{>name}} {{>releaseYear}}
	{{for languages}}
		{{>name}}
	{{/for}}

6. If you want to access the parent, use {{>#parent.parent.data}}

	{{>name}} {{>releaseYear}}
	{{for languages}}
		{{>#parent.parent.data.name}} {{>name}}
	{{/for}}

7. You can also access use context variables to access the parent.

	{{>name}} {{>releaseYear}}
	{{for languages ~movieName=name}}
		{{>~movieName}} {{>name}}
	{{/for}}

8. If you want to use templates inside a template, use the tmpl attribute.

	<script id="languageTemplate" type="text/x-jsrender">
		{{>name}}
	</script>

	....

	{{>name}} {{>releaseYear}}
	{{for languages tmpl="#languageTemplate" /}}

9. You can create helper functions.

	<script type="text/javascript">
		$.views.helpers({
			toUpper: function(val) {
				return val.toUpperCase();
			}
		});
	</script>

	...

	{{>~toUpper(name)}} {{>releaseYear}}

10. You can create custom tags.

	<script type="text/javascript">
		$.views.tags({
			toUpper: function(val) {
				return val.toUpperCase();
			}
		});
	</script>

	...

	{{toUpper name /}} {{>releaseYear}}

11. If you want to access the data passed to the render function, use #data.

	{{for #data}}
		<li>
			{{>name}} {{>releaseYear}}
		</li>
	{{/for}}

12. You can also pass parameters and functions to the render function.

	{{>~label}} {{>name}} {{>releaseYear}}

	...

	$("#movieTemplate").render(movies, { label: "Movie: " })

13. If you wish to loop through an array inside the template instead of JsRender, wrap your data in an array.

	$("#movieTemplate").render([movies]);

That wraps up our quick overview of JsRender. For advanced features and more examples, please look at the official JsRender demos.


Console Object on IE

Here’s the JavaScript you need to avoid console errors in browsers that lack a console. This is taken from HTML5 Boilerplate 4, in plugins.js.

	if (!(window.console && console.log)) {
		(function() {
			var noop = function() {};
			var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
			var length = methods.length;
			var console = window.console = {};
			while (length--) {
				console[methods[length]] = noop;
			}
		}());
	}

If you use jQuery, you can use a more terse version.

	if (!(window.console && console.log)) {
		window.console = {};
		$.each(['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'], function() {
			window.console[this] = $.noop;
		});
	}

If you are only worried about console.log, then you can use

	if (!(window.console && console.log)) {
		window.console = {
			log: function(param) {}
		};
	}


window.onhashchange, jQuery hashchange, history.pushState and History.js

If you wish to make your AJAX website bookmark and back button friendly, you will need to use location.hash or history.pushState. Below are some short examples of how it all works.

1. Before HTML5, we needed to use onhashchange. Here’s an example of how this works. Notice we start the hash with a “!” to enable Google AJAX crawling.

<!DOCTYPE html>
<html>
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
	<script>
		$(function() {
			window.onhashchange = function () {
				alert("onhashchange = " + window.location.hash); // do something on click
			}

			alert("onload = " + window.location.hash); // do something onload

			$('#link').click(function(e) {
				e.preventDefault();
				window.location.hash = '!hello';
			});
		});
	</script>
</head>
<body>
	<a href="#" id="link">change</a>
</body>
</html>

2. If you would like a jQuery solution, you can use the jQuery hashchange plugin.

<!DOCTYPE html>
<html>
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
	<script src="http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js"></script>
	<script>
		$(function() {
			$(window).hashchange(function() {
				alert("hashchange = " + window.location.hash); // do something on hashchange
			})

			$(window).hashchange(); // force hashchange onload

			$('#link').click(function(e) {
				e.preventDefault();
				window.location.hash = '!hello';
			});
		});
	</script>
</head>
<body>
	<a href="#" id="link">change</a>
</body>
</html>

3. HTML5 introduced history.pushState, which allows you to change URLs without using hashes.

<!DOCTYPE html>
<html>
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
	<script>
		$(function() {
			window.onpopstate = function() {
				alert("onpopstate = " + window.location.href); // do something onpopstate
			};

			alert("onload = " + window.location.href); // do something on load

			$('#link').click(function(e) {
				e.preventDefault();
				history.pushState(null, null, 'hello.html');
				alert("pushState = " + window.location.href); // do something on click
			});
		});
	</script>
</head>
<body>
	<a href="#" id="link">change</a>
</body>
</html>

Don’t try this by opening a local HTML, where you see file:// in the browser URL, or you might get some security issues. The onload alert is needed on Firefox, but is redundant in Chrome and Safari.

4. If you would like a solution that will use history.pushState for modern browsers but fallback to onhashchange if history.pushState is not supported, try History.js. Make sure you first download and make jquery.history.js available, and don’t test this on a URL that starts with file://.

<!DOCTYPE html>
<html>
<head>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
	<script src="history.js/scripts/bundled/html4%2Bhtml5/jquery.history.js"></script>
	<script>
		$(function() {
			window.History.Adapter.bind(window, 'statechange', function() {
				alert("statechange = " + window.location.href); // do something on statechange
			});

			alert("load = " + window.location.href); // do something on load

			$('#link').click(function(e) {
				e.preventDefault();
				window.History.pushState(null, null, 'hello.html');
			});
		});
	</script>
</head>
<body>
	<a href="#" id="link">change</a>
</body>
</html>

Now you got a glimpse of how these work, I suggest you read Must-Know URL Hash Techniques for AJAX Applications, which gives an overview of the whole workflow.