Is there a best practice for generating html with javascript

I'm calling a web service that returns an array of objects in JSON. I want to take those objects and populate a div with HTML. Let's say each object contains a url and a name.

If I wanted to generate the following HTML for each object:

<div><img src="the url" />the name</div>

Is there a best practice for this? I can see a few ways of doing it:

  1. Concatenate strings
  2. Create elements
  3. Use a templating plugin
  4. Generate the html on the server, then serve up via JSON.

Answers:

Answer

Options #1 and #2 are going to be your most immediate straight forward options, however, for both options, you're going to feel the performance and maintenance impact by either building strings or creating DOM objects.

Templating isn't all that immature, and you're seeing it popup in most of the major Javascript frameworks.

Here's an example in JQuery Template Plugin that will save you the performance hit, and is really, really straightforward:

var t = $.template('<div><img src="${url}" />${name}</div>');

$(selector).append( t , {
     url: jsonObj.url,
     name: jsonObj.name
});

I say go the cool route (and better performing, more maintainable), and use templating.

Answer

If you absolutely have to concatenate strings, instead of the normal :

var s="";
for (var i=0; i < 200; ++i) {s += "testing"; }

use a temporary array:

var s=[];
for (var i=0; i < 200; ++i) { s.push("testing"); }
s = s.join("");

Using arrays is much faster, especially in IE. I did some testing with strings a while ago with IE7, Opera and FF. Opera took only 0.4s to perform the test, but IE7 hadn't finished after 20 MINUTES !!!! ( No, I am not kidding. ) With array IE was very fast.

Answer

Either of the first two options is both common and acceptable.

I'll give examples of each one in Prototype.

// assuming JSON looks like this:
// { 'src': 'foo/bar.jpg', 'name': 'Lorem ipsum' }

Approach #1:

var html = "<div><img src='#{src}' /> #{name}</div>".interpolate(json);
$('container').insert(html); // inserts at bottom

Approach #2:

var div = new Element('div');
div.insert( new Element('img', { src: json.src }) );
div.insert(" " + json.name);
$('container').insert(div); // inserts at bottom
Answer

Perhaps a more modern approach is to use a templating language such as Mustache, which has implementations in many languages, including javascript. For example:

var view = {
  url: "/hello",
  name: function () {
    return 'Jo' + 'hn';
  }
};

var output = Mustache.render('<div><img src="{{url}}" />{{name}}</div>', view);

You even get an added benefit - you can reuse the same templates in other places, such as the server side.

If you need more complicated templates (if statements, loops, etc.), you can use Handlebars which has more features, and is compatible with Mustache.

Answer

Here's an example, using my Simple Templates plug-in for jQuery:

var tmpl = '<div class="#{classname}">#{content}</div>';
var vals = {
    classname : 'my-class',
    content   : 'This is my content.'
};
var html = $.tmpl(tmpl, vals);
Answer

You could add the template HTML to your page in a hidden div and then use cloneNode and your favorite library's querying facilities to populate it

/* CSS */
.template {display:none;}

<!--HTML-->
<div class="template">
  <div class="container">
    <h1></h1>
    <img src="" alt="" />
  </div>
</div>

/*Javascript (using Prototype)*/
var copy = $$(".template .container")[0].cloneNode(true);
myElement.appendChild(copy);
$(copy).select("h1").each(function(e) {/*do stuff to h1*/})
$(copy).select("img").each(function(e) {/*do stuff to img*/})
Answer

Disclosure: I am the maintainer of BOB.

There is a javascript library that makes this process a lot easier called BOB.

For your specific example:

<div><img src="the url" />the name</div>

This can be generated with BOB by the following code.

new BOB("div").insert("img",{"src":"the url"}).up().content("the name").toString()
//=> "<div><img src="the url" />the name</div>"

Or with the shorter syntax

new BOB("div").i("img",{"src":"the url"}).up().co("the name").s()
//=> "<div><img src="the url" />the name</div>"

This library is quite powerful and can be used to create very complex structures with data insertion (similar to d3), eg.:

data = [1,2,3,4,5,6,7]
new BOB("div").i("ul#count").do(data).i("li.number").co(BOB.d).up().up().a("a",{"href": "www.google.com"}).s()
//=> "<div><ul id="count"><li class="number">1</li><li class="number">2</li><li class="number">3</li><li class="number">4</li><li class="number">5</li><li class="number">6</li><li class="number">7</li></ul></div><a href="www.google.com"></a>"

BOB does currently not support injecting the data into the DOM. This is on the todolist. For now you can simply use the output together with normal JS, or jQuery, and put it wherever you want.

document.getElementById("parent").innerHTML = new BOB("div").insert("img",{"src":"the url"}).up().content("the name").s();
//Or jquery:
$("#parent").append(new BOB("div").insert("img",{"src":"the url"}).up().content("the name").s());

I made this library because I was not pleased with any of the alternatives like jquery and d3. The code very complicated and hard to read. Working with BOB is in my opinion, which is obviously biased, a lot more pleasant.

BOB is available on Bower, so you can get it by running bower install BOB.

Answer

Is there a best practice for this? I can see a few ways of doing it:

  1. Concatenate strings
  2. Create elements
  3. Use a templating plugin
  4. Generate the html on the server, then serve up via JSON.

1) This is an option. Build up the html with JavaScript on the client side and then inject it in the DOM as a whole.

Note that there is a paradigm behind this approach: the server outputs just data and (in case of interaction) receives data from the client asyncronoulsy with AJAX requests. The client side code operete as a stand-alone JavaScript web application.

The web application may operate, render the interface, even without the server being up (of course it won't display any data or offer any kind of interaction).

This paradigm is getting adopted often lately, and entire frameworks are build around this approach (see backbone.js for example).

2) For performance reasons, when possible, is better to build the html in a string and then inject it as a whole into the page.

3) This is another option, as well as adopting a Web Application framework. Other users have posted various templating engines available. I have the impression that you have the skills to evaluate them and decide whether to follow this path or not.

4) Another option. But serve it up as a plain text/html; why JSON? I don't like this approach because mixes PHP (your server language) with Html. But I adopt it often as a reasonable compromise between option 1 and 4.


My answer: you are already looking in the right direction.

I suggest to adopt an approach between 1 and 4 like I do. Otherwise adopt a web framework or templating engine.

Just my opinion based on my experience...

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.