views:

543

answers:

2

There is a maintanble approach to build DOM with jQuery? Take a look at the append method of this code...

$.getJSON("api/test", function(data) {
    $.each(data, function () {
        $("#tests").append($('<tr><td><input type="radio" name="' + this["name"] + '"/><td>' + this["name"] + '</td><td>' + this["descr"] + '</td></tr>'));
    });
});

I think (or at least I hope) there's a better way. Can you refactor this to be more legible?

+2  A: 

Look at the template plugin.

http://plugins.jquery.com/project/jquerytemplate

Your code can now look like,

$.getJSON("api/test", 
    function(data) 
    {
        var t = $.template('<tr><td><input type="radio" name="{name}"/><td>{name}</td><td>{descr}</td></tr>');
        $.each(data, function () 
        {
            $("#tests").append(t, this);
        }
    }
  );

EDIT

As redsquare correctly points out, if you have large number of rows, doing DOM manipulation in each iteration can be really slow. Don't change your code unless you have profiled your code and found this particular loop to be the bottleneck.

If I borrow the 'string.Format' method from this post, you can do something like

$.getJSON("api/test", 
    function(data) 
    {
        var template = '<tr><td><input type="radio" name="{name}"/><td>{descr}</td><td>{1}</td></tr>';
        var html = [];
        $.each(data, function () 
        {
            html.push(template.format(this));
        }
        $('#tests').append(html.join(''));
    }
  );

EDIT: Modified the string.Format function to take name based key. Now your template code can use {name}, {descr} instead of using {0}, {1}. The function will try to find the property with the same name in the argument passed to the function.

Also, look at Rick Strahl's approach and see if it makes more sense to you.

http://www.west-wind.com/WebLog/posts/300754.aspx

SolutionYogi
+1: I like it, thanks
dfa
Great. So will you accept the answer? :)
SolutionYogi
I like also choices :P
dfa
This is an inefficient way of doing this. It is far better to either use a string or better still to push to an array and append just the once. With large set of data this will crawl
redsquare
+2  A: 

I would not append inside the each. It is better to either use a stringbuilder or push to an array and append once with .join()

The choice depends which browser your trying to optimize for. Appending to the DOM is quite invasive due to screen reflows therefore I would minimize the amount of times I call the .append.

There are many performance comparisons on the web that go into detail over the performance of both options. One here.

Example of array join

$.getJSON("api/test", 
    function(data) 
    {
        var rowsToAppend=[];

        $.each(data, function () 
        {
            rowsToAppend.push( '<tr><td></td></tr>' );
        }

        $("#tests").append( rowsToAppend.join() );
    }
  );
redsquare
Yes, doing several DOM manipulations inside a loop will be really slow. But in your post, you didn't take care of the author's original problem.
SolutionYogi
I'm sure he can work out the markup to push to the array. The key point was not to lead him down the slow path.
redsquare
You are missing the key point from the author's question. He didn't complain that the code is slower, he felt that keeping the HTML that way was not maintainable and I can imagine why. I am not saying that you haven't raised a valid point about doing dom manipulation in a loop, but saying that he can figure out 'markup' problem means that you didn't even answer the original question.
SolutionYogi
+1. Good simple advice.
Chetan Sastry