0

I've been looking into JavaScript templating libraries like dust.js and other more extensive libraries like canJS

Where I work we do nearly 99% of any application / site on the client side. Currently I just build strings of html, inject into the dom, listen for clicks / actions, do ajax, build more strings of html from the results and inject into the dom and so on.

If you take this simple example.

//stringbuilder
function StringBuilder(e){this.strings=new Array("");this.append(e)}StringBuilder.prototype.append=function(e){if(e){this.strings.push(e)}};StringBuilder.prototype.clear=function(){this.strings.length=1};StringBuilder.prototype.toString=function(){return this.strings.join("")}

var data = {
    fname: "Joe",
    lname: "Doe",
    occupation: "Developer",
    things: ["some", "list", "of", "things"]
}

var sb = new StringBuilder();

sb.append("<h1>" + data.fname + " " + data.lname + "</h1>");
sb.append("<p>Occupation: " + data.occupation + "</p>");
sb.append("<h3>A list of things</h3>");
sb.append("<ul>");
for (var i = 0; i < data.things.length; i++) {
    sb.append("<li>" + data.things[i] + "</li>");
}
sb.append("</ul>");

$("#output").html(sb.toString());

In what way could this be improved by templating? From what I've seen I would have to adapt to a particular template syntax which isn't any easier to read or maintain than the above. What about complex layouts, or scenarios where you have recursion (lists within lists without knowing how many levels it may go). I feel the templating syntax / engine my be a limiting factor in some cases.

I suppose it's nice to pull that html out of the JS completely, but lets say using script tags with the template syntax inside the HTML is off the table, I don't particularly want the templates as external files I need to perform extra requests to read.

Please educate me!

MNasir
  • 137
  • 7
Fergal
  • 2,484
  • 2
  • 36
  • 48

3 Answers3

6

Well, just compare:

sb.append("<h1>" + data.fname + " " + data.lname + "</h1>");
sb.append("<p>Occupation: " + data.occupation + "</p>");
sb.append("<h3>A list of things</h3>");
sb.append("<ul>");
for (var i = 0; i < data.things.length; i++) {
    sb.append("<li>" + data.things[i] + "</li>");
}
sb.append("</ul>");

To

<h1>@fname @lname</h1>
<p>Occupation: @occupation</p>
<h3>A list of things</h3>
<ul>
    @foreach( thing in things ) {
        <li>@thing</li>
    }
</ul>

Which looks more maintainable to you?

demo

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • 2
    I think this question is a prime example of Aversion to New Things. Methinks OP is not so easily convinced :) – jevakallio Dec 18 '12 at 00:23
  • @fencliff Yeah I guess you have to be really stubborn not to be convinced by this.. this syntax supports dropping into arbitrary javascript at any time, helper functions, imports/exports, plus all control structures from javascript with `@foreach` being necessary addition – Esailija Dec 18 '12 at 00:30
  • Thanks, didn't come across attemplate in my searches. Right off the bat it looks like something that can defeat my stubbornness. template.fromString is perfect for me, as I said it might not always be possible to have templates in the DOM itself. Also template syntax is much cleaner than anything else I've seen. – Fergal Dec 18 '12 at 00:49
  • @Fergal Well I should probably mention it's my library and I haven't touched it in a while, I mean I do use it in production but there's a few gotchas like having to manually html escape `@()`-expressions (I.E. `@( htmlEncode(something))` ) and not being able to use `;` inside a do-while. Both of these are mentioned in the documentation though. – Esailija Dec 18 '12 at 00:54
1

By using dust.js you can create a template file which looks like this:

<h1>{fname} {lname}</h1>
<p>Occupation: {occupation}</p>
<h3>Friends list:</h3>
<ul>
  {#friends}
  <li>{name} {age}</li>
  {/friends}
</ul>

Your JSON data:

var data = {
  fname: "Joe",
  lname: "Doe",
  occupation: "Developer",
  friends: [
    {
      name: "Moe",
      age: 37 
    },
    { 
      name: "Larry",
      age: 39
    },
    {
      name: "Curly",
      age: 35
    }
  ]
}

And to render your template simply call dust.render and pass the template_name along with JSON object and callback function:

dust.render('template_name', data, function(err, out){
  $("#output").html(out);
});

Another useful and related question: how to use dustjs-linkedin as client side templating?

Community
  • 1
  • 1
Omid Monshizadeh
  • 1,514
  • 1
  • 10
  • 12
0

in Mustache.js this template:

sb.append("<h1>" + data.fname + " " + data.lname + "</h1>");
sb.append("<p>Occupation: " + data.occupation + "</p>");
sb.append("<h3>A list of things</h3>");
sb.append("<ul>");
for (var i = 0; i < data.things.length; i++) {
    sb.append("<li>" + data.things[i] + "</li>");
}
sb.append("</ul>");

is moved to the DOM and would look like this in your IDE:

<script id="sb">
    <h1>{{fname}} {{lname}}</h1>
    <p>Occupation: {{occupation}}</p>
    <h3>A list of things</h3>
    <ul>
    {{#things}}
        <li>{{.}}</li>
    {{/things}}
    </ul>

</script>

It will maintain your code highlighting in the IDE and will be much easier to read without the "<div>"s

You render this by using:

var output = Mustache.render($("sb").html(), data);
$("#destination").html(output);
Patrick Gunderson
  • 3,263
  • 17
  • 28