0

I need to create an HTML output composed of nested DIVs, when provided with an array of objects.

At the moment I am using the following code, it works. This example it is very simplistic as in the production, I have many objects and complex HTML to be created and initialized.

At the moment I am using two loops, one for opening and one for closing DIVs.

I would like to know if you could suggest me also an alternative approach, considering performances, example avoiding the double loop and so on.

        (function () {
            var html = '';
            var data = [{ id: 'a' }, { id: 'b' }, { id: 'c' }];

            function open(item) {
                html += '<div id="' + item.id + '">';
            }
            function close(item) {
                html += '</div>';
            }

            for (var i = 0, len = data.length; i < len; i++) {
                open(data[i]);
            }
            for (var i = 0, len = data.length; i < len; i++) {
                close(data[i]);
            }
            alert(html);
            /* RESULT
            <div id="a">
                <div id="b">
                    <div id="c">
                    </div>
                </div>
            </div>
            */

        })();
GibboK
  • 71,848
  • 143
  • 435
  • 658
  • is there a reason you create a HTML-String and not over the [DOM functions](http://stackoverflow.com/questions/2690352/which-is-better-string-html-generation-or-jquery-dom-element-creation)? – pce Jul 23 '15 at 13:21
  • I will use Element.innerHtml only once on the parent node in order to replace its content with HTML output create by this function. I am ware of the performance issue when using Element.innerHtml in a loop. Thanks all for your time on this. – GibboK Jul 23 '15 at 13:51

4 Answers4

4

A classical case for recursion, I think.

function createHTML(data) {
    var item = data.shift(), div, child;

    if (item) {
        div = document.createElement("DIV");
        div.id = item.id;
        child = createHTML(data, div);
        if (child) div.appendChild(child);
        return div;
    }
}

createHTML([{ id: 'a' }, { id: 'b' }, { id: 'c' }]);

Building HTML from concatenated strings is more error-prone than using DOM methods to do it, especially with respect to malicious or unintentionally broken inputs. Therefore I generally prefer DOM methods.

Which method is fastest - that's up to you to measure, but I would recommend sacrificing pure speed over correct and resilient code.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
1

Use Document Fragment like this

var i = 0,
    fragment = document.createDocumentFragment();
var data = [{
    id: 'a'
}, {
    id: 'b'
}, {
    id: 'c'
}];

for (var i = 0, len = data.length; i < len; i++) {
    var el = document.createElement('div');
    el.id = data[i].id;
    //el.innerHTML = data[i].id;
    if(i>0 && fragment.getElementById(data[i-1].id)){
        fragment.getElementById(data[i-1].id).appendChild(el);
    } else {
    
    fragment.appendChild(el);
    }
}

document.body.appendChild(fragment);
#a {
   border: 1px solid red;
    padding:5px;
}

#b {
  border: 1px solid green;
    padding:5px;
}

#c {
   border: 1px solid blue;
    padding:5px;
}
dimshik
  • 1,251
  • 15
  • 17
0

you can do it in one loop

(function () {
    var html = '';
    var html1 = '';
    var data = [{
        id: 'a'
    }, {
        id: 'b'
    }, {
        id: 'c'
    }];

    function open(item) {
        html += '<div id="' + item.id + '">';
        html1 += '</div>';
    }

   // function close(item) {
   //     html += '</div>';
   // }

    for (var i = 0, len = data.length; i < len; i++) {
        open(data[i]);
    }
    //for (var i = 0, len = data.length; i < len; i++) {
    //    close(data[i]);
    //}
    alert(html+html1);
    /* RESULT
            <div id="a">
                <div id="b">
                    <div id="c">
                    </div>
                </div>
            </div>
            */

})();
ozil
  • 6,930
  • 9
  • 33
  • 56
-1

DocumentFragment

Why you should always append DOM elements using DocumentFragments.

(function () {
  var frag = document.createDocumentFragment();
  var data = [{ id: 'a', value: 'A' }, { id: 'b', value: 'B' }, { id: 'c', value: 'C' }];
  for (var i = 0, len = data.length; i < len; i++) {
    var div = document.createElement("div");
    div.innerHTML = data[i].value;
    div.id = data[i].id;
    frag.appendChild(div);
  }
  document.body.appendChild(frag);
})();
DonSinDRom
  • 271
  • 5
  • 12