views:

60

answers:

2

When creating a web page who's content will be created and destroyed dynamically by the user, what is the best way to structure and initialize both the javascript functionality and the DOM Elements?

Example -- Lets say you have a todo-list who's items can be re-ordered, created, and destroyed by the user:

  • Each Item will have a visual representation (ie. Dom elements) which will need to be created dynamically when the user adds an item
  • Each item will also have a javascript representation (ie. javascript objects with custom methods and attributes) which will be instantiated when the user adds an item

What is the bet way to deal with creating the initial DOM elements and their javascript representation? I can see a couple possibilities:

  • have the server spit out the structured HTML and have the JS glean the initial state by walking the DOM.
  • have the server spit out the structured HTML and some JS code to create the set of objects and associate them with their DOM representation.
  • have the server spit out JS objects and dynamically create the DOM elements once the page is loaded.
+1  A: 

I'm not sure about best way; it depends on what your requirements are.

My favorite approach is to have a JavaScript template for each data structure; that way, if you're doing AJAX calls, the only thing you have to send across the wire is data itself, and not HTML.

You could also use a hybrid approach where the server spits out the structured HTML for initial page load, read the structure in (you should have enough semantic meaning in your HTML to know what it is you're dealing with, even if you don't use this approach), but still use JavaScript templates to stuff data into for updates. The obvious downside to this approach is that you will end up duplicating your templates on the client and server-side; however, there are tools and frameworks (e.g. Google Closure Templates) that allow you to write the templates once and will generate the appropriate server and client versions for you. You will have to send the HTML from the server if you want your application to work without JavaScript. If you are requiring JavaScript, I don't see a reason to have the server spit out the HTML unless you're worried about multiple HTTP requests.

Whether you want to send the JavaScript structure and the HTML for initial page load therefore depends on several factors: what CPUs are you targetting? (desktop, mobile) What type of bandwidth will your clients have? (sub-3G speeds?) If you have unlimited bandwidth but limited CPU, it would make more sense to send both the structure and data on first page load. If you had unlimited CPU but limited bandwidth, you'd only want to send either the structure or the data and generate the other from it, etc.

You could also use something like GWT or jQuery's widgets to handle a lot of this pain for you, but they're all the same kind of idea: only have one copy of the HTML layout per widget/structure/whatever-you-want-to call-it so that the data itself stays lean and nice to work with.

Of course, the fewer HTTP requests you can get away with, the better, but that can lead to quite a bit of complexity and duplication in your code unless you use a framework or toolkit or roll your own.

Nate Bundy
Good points. In this case, the amount of data and the number of elements on the page is quite small, only using JSON for data transport and having the local javascript create the visual representation in the DOM seemed simplest. Having the same HTML template in both the client and the server seemed redundant, so I stuck with the client.
Daniel Beardsley
+1  A: 

Performance-wise, you'll do best using your 3rd option - Creating the DOM elements dynamically. First, because the server response will be smaller, and thus quicker, and second because JavaScript performance will be better in creating the objects.

Looking at performance when you just need to inject elements into a page, comparing this:

element.appendChild(document.createElement("div"));

to this:

element.innerHTML = "<div></div>";

innerHTML is quicker. However, when you need references to the injected elements, comparing this:

var child = element.appendChild(document.createElement("div"));

to this:

element.innerHTML = "<div id=\"" + childId + "\"></div>";
var child = document.getElementById(childId);

createElement wins the performance contest.

Since you need element references, you'll get better performance from retrieving JSON from the server, and creating the elements.

That being said, you may get the best performance by only creating the elements you need references to and injecting html elsewhere. Eg, for this html:

<div>
    <div class="a">Item A</div>
    <div class="b">Item B</div>
</div>

If you only need a reference to the parent <div>, and not to its children, then rather than creating the child elements dynamically, create the parent <div> dynamically, and then set its innerHTML for the content:

var item = serverObject[i];
var el = parent.appendChild(document.createElement("div"));
el.innerHTML = "<div class=\"" + 
    item.A.className + "\">" +
    item.A.text + "</div><div class=\"" +
    item.B.className + "\">" +
    item.B.text + "</div>";

Thus, you get the best of both worlds, performance-wise.

Edit - Adding information beyond performance considerations

Architecturally speaking, I don't like services to know much about the client, only the data it provides. This way, if you decide to change your UI, you don't have to muck with the service to get it to spit out different HTML. Additionally, should you find that you want to use the same data elsewhere, you've already got a service in place that you could re-use.

gilly3
Thank you for this answer, performance is an important part and it's good to know what's fastest. Though I was intending this question to be more about choosing whether to spit out HTML from the server and use that to build the data structure, spit out JS and create HTML from that, or spit out both HTML and JS.
Daniel Beardsley
I've added some notes at the bottom about architectural considerations. I'm all for the service sending data only to the client, and not UI (Ie, HTML). I'd use your third option performance and architectural reasons.
gilly3