John Resign created some incredibly wonderful Javascript code for templating. It’s so terse that it almost shouldn’t work…but it does. I’ve been using it on a lot of front-end JS apps lately, and realized I could make a few changes and improvements.

First off, I don’t like <% asp style tags %>. It reminds me of programming ASP. It reminds me of a trip through hell I’ve taken too many times. I changed it to use PHP-style tags instead:

<ul class="<?=myclass?>">
<? for(var i = 0; i < items.length; i++) { ?>
    <li><?=items[i].name?>
<? } ?>
</ul>

This makes it easier for me to type. I also made one further modification. Adding $ in front of your variables will check if they are undefined before using them, and if not defined will return them as null:

Hello, <?=$name?>.
<? if($user.friends) { ?>
    You have <?=$user.friends.length?> friends.
<? } ?>

The if statement above will compile to

if((typeof(user.friends) == 'undefined' ? null : user.friends)) { ... 

This allows some simple usages of undefined variables, such as “if(undefined_var) { … } else { … }” which actually pops up a lot. You still can’t access non-existent properties of variables that aren’t defined, but this should catch a lot of errors that would otherwise turn your code into a bunch of if(typeof …)’s.

Here’s the code (for brevity, I left out all the caching stuff that makes this fast):

var template = '<h1>My Template</h1> ...';
new Function(
	"obj",
	"var p=[],print=function(){p.push.apply(p,arguments);};" +
	// Introduce the data as local variables using with(){}
	"with(obj) {p.push('" +
	// Convert the template into pure JavaScript
	template.replace(/[\r\t\n]/g, " ")
		// find any code blocks (not html, not <?=print_var?>... anything inside a
		// <? ... ?>
		.replace(/<\?(.*?)\?>/g, function(match) {
			// look for any string starting with a "$" and wrap it in a ternary typeof op
			return match.replace(/\$([a-z_][a-z0-9_\.]+)/gi, '(typeof($1) == "undefined" ? null : $1)');
		})
		.split("<?").join("\t")
		.replace(/((^|\?>)[^\t]*)'/g, "$1\r")
		.replace(/\t=\$?(.*?)\?>/g, "',(typeof($1) != 'undefined' ? $1 : ''),'")
		.split("\t").join("');")
		.split("?>").join("p.push('")
		.split("\r").join("\\'") + "');}"
		//+ "console.log('Loading template " + name + "');"
		+ "return p.join('');"
);

This has been working for me for a bit now, and has saved me countless annoying declarations at the top if my templates. If you run into any problems, please let me know.

Trackback

OMGOSH 2 comments

  1. My name is Lindsay, and I’m the Community Manager at DZone.com, a website that offers content and links to the development and software community. I’d like to tell you about our Most Valuable Bloggers program, a free program that brings content from excellent blogs such as yours to our audience. If you are interested please e-mail me at lgordon@dzone.com. I hope to hear from you!

  2. Hi there! My name is Lindsay, and I’m the Community Manager at DZone.com, a website that offers content and links to the development and software community. I’d like to tell you about our Most Valuable Bloggers program, a free program that brings content from excellent blogs such as yours to our audience. If you are interested please e-mail me at lgordon@dzone.com. I promise that this isn’t spam, and I hope to hear from you!

Add your comment now