April 5, 2009 will

Django like templates in Javascript

Here's a quick ‘n’ dirty Javascript function I hacked together that provides Django-like template substitution.

function sformat(template, data)
{
    return template.replace(/{{(.*?)}}/g, function(m, n) {
        return eval('data.'+n);
        });
}

Used something like this:

sformat("Hello, {{ name }}!", {name:"World"});

Which returns the following string:

Hello, World!

Alas, it doesn't support anything other than substitution. If you need anything more advanced (loops etc), you should investigate Javascript template engines.

Use Markdown for formatting
*Italic* **Bold** `inline code` Links to [Google](http://www.google.com) > This is a quote > ```python import this ```
your comment will be previewed here
gravatar
Christof
I think eval is somehow evil (and slow). I guess a better substitute would be to simply use ``return data;``. Should be the same, although I have not tested it.
gravatar
Christof
Sorry, bbcode messed up my post, should have been:
 return data[n]
gravatar
Fraser
As Christof says, the use of eval in this case is inadvisable as it leaves you vulnerable to injection attacks. For example, the following would result in an alert dialog being shown:

 sformat(
  "Hello, {{ name; alert('Nasty code goes here') }}!",
  {name:"World"}
);

gravatar
eelco
How about this one instead:
http://dojotoolkit.org/book/dojo-book-0-9/part-5-dojox/dojox-dtl
gravatar
Dougal Matthews
I'm not really sure why anybody would want to do this?

Care to share a usecase?
gravatar
Will McGugan
Christof, the reason I went with eval is that it could handle nested objects. so something like “{{ post.body }}” would work.

Fraser, granted, although if the template doesn't come from an external source like an AJAX request, it shouldn't be an issue.

eelco, that's pretty neat.

Dougal, its more elegant than string concatenation, IMHO.

 html = sformat("<h1>{{ post.header }}</h1><p>{{ post.body }}</p>", {post:post});
Verus:
 html="<h1>" + post.header + "</h1><p>" + post.body + "</p>";
gravatar
rgz
Yay! So I'm not that crazy! I wrote this one for all my js applications, note that it doesn't affect the original string (the first version did), also note that unmatched fields are left in the result, this is to use it in further substitutions, i.e. for writing template templates.
 /**
 * Template format tf
 * @argument values {object} Completa la plantilla con un objeto tipo diccionario.
 */
String.prototype.tf = function(values){
    var text = this.toString()
    for (var name in values){
        text = text.replace(new RegExp("{" + name + "}"  , ['g']), values[name])
    }
    return text
}
gravatar
WIll McGugan
RGZ, great minds think alike or fools seldom differ? ;-)
gravatar
m0n5t3r
When I needed something like that, I went with python-style sprintf (named arguments) and wrote a jQuery plug-in :)

so my code would look like
 var s1 = $.sprintf('Hello, %(name)s!', {'name': 'world'});
// or, simpler:
var s2 = $.sprintf('Hello, %s!', 'world');

the less typing, the better :D