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.
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!
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!