Armin Ronacher

ERB for JavaScript

written by Armin Ronacher, on Thursday, June 14, 2007 14:18.

Today I found this at reddit and was stunned by the way it was implemented. I now created a similar implementation, it's just a little smaller, supports escaping and doesn't use an evil delimiter hack and it also supports all of the ERB goodness including the leading-percent sign block support.

Example:

var template = new JSTemplate('\\
  <%# This is a nice little comment %>\\
  <p>Total number of users: &lt;%= this.users.length %&gt;</p>\\
  <ul>\\
  &lt;% each(this.users, function(user, idx) { %&gt;\\
    <li>#&lt;%= idx + 1 %&gt; &lt;%= escape(user) %&gt;</li>\\
  &lt;% }) %&gt;\\
  </ul>\\
  <p>Last updated on: &lt;%= this.lastUpdate %&gt;\\
');
document.getElementById('output').innerHTML = template.render({
  users:        ['H4&gt;&lt;0r', 'peter', 'anton'],
  lastUpdate:   new Date()
});
Available helper functions are <tt>each</tt> and <tt>escape</tt>, now guess what they do.

Sourcecode is here: <a href="http://lucumr.pocoo.org/trac/repos/jstemplates/">jstemplates</a>

<strong>Update:</strong> It can process ERB % statements now too.</p>

Comments

  1. Very cool bit of code. I was fooling with it, trying to load the template text using an XMLHttpRequest, with the target document just a plain text document containing the markup, but I was having issues with preparing the template string to instantiate JSTemplate. To make it work for me I had to prepare the responseText as follows:

    <pre>
    var req=new XMLHttpRequest();
    req.open("GET", "sample.jst",false);
    req.send(null);
    var txt=req.responseText;
    txt=txt.replace(/[\\n\\r]/g,""); //!!!!IMPORTANT
    var template=new JSTemplate(txt);
    document.getElementById('output').innerHTML=
    template.render({
    users: ['H4>
    </pre>

    —  David Edelstein on Tuesday, July 10, 2007 1:36 #

  2. In theory the newline replacement shouldn't be necessary. I wonder which browser you're using, probably the parser has to cope with the carriage return character too.

    —  Armin Ronacher on Wednesday, July 11, 2007 22:05 #

  3. Hrm, your comment system cut off half my comment, I think that it didn't like that those > < in H4><or (so im going to use html-entities)....Anyways, It was word for word from your example code and you caught my drift anyways.

    I'm using firefox, but maybe I should see how IE does it, but I doubt that it would work as expected either.

    More interestingly though, your script does some pretty neat stuff that you didn't include in your example. check this example template out and you'll see that it works too!

    <pre><% this.fcn=function(){%><p>P function called</p><%} ;%>\\ <%# This is a nice little comment %>\\ <p>Total number of users: <%= this.users.length %></p>\\ <ul>\\ <% each(this.users, function(user, idx) { %>\\ <li>#<%= idx + 1 %> <%= escape(user) %></li>\\n\\
    <% }) %>\\
    </ul>\\
    <%this.fcn();%>\\
    <p>Last updated on: <%= this.lastUpdate %>\\ ');</pre>

    I also made an iif function to include along with each and escape (can leave out the else function and this still works):

    <pre> function iif(cond, tstmt, fstmt) {
    if(cond){
    return t_stmt();
    }else if(f_stmt){
    return f_stmt();
    }
    }</pre>

    example:

    <pre> <% iif(true,function(){%><br>is true<%}, function(){%><br>is false<%}) %>\\</pre>

    you can even use the iif function using a template function as a parameter and it works too!

    very nice.

    • Dave

    —  David Edelstein on Thursday, July 12, 2007 14:12 #

  4. Hiya, wanted this working in IE6 and found a couple things that made it work: -the split function doesn't behave properly with regexp captures (used blog.stevenlevithan.com/archives/cross-browser-split to fix) -indexing strings in IE doesn't work, so replaced all string indexes (part[0], etc.) w/ part.charAt(0) -eval function in IE doesn't work, fix is at arrix.blogspot.com/2007/04/eval-bug-in-ie.html

    —  Charles Cooke on Sunday, July 22, 2007 22:58 #

Leave a Reply