21

Given these javascript variables:

var div_id = "my_div";
var h1_class = "my_header";
var a_class = "my_a_class";
var a_string = "teststring";

and this page element:

<div id="container"></div>

I want to build this html structure with jQuery:

<div id="container">
    <div id="my_div">
        <h1 class="my_header">
            <a href="/test/" class="my_a_class">teststring</a>
        </h1>
    </div>
</div>

What is the best and most readable way to chain the commands here?

Thaddeus Albers
  • 4,094
  • 5
  • 32
  • 42
Hobhouse
  • 15,463
  • 12
  • 35
  • 43

9 Answers9

20

UPDATED

JSON

        var widgets = [{
            "div" : {
                "id" : "my-div-1"
            },
            "h1" : {
                "class" : "my-header"
            },
            "a" : {
                "class" : "my-a-class",
                "text" : "google",
                "href" : "http://www.google.com"
            }
        }, {
            "div" : {
                "id" : "my-div-2"
            },
            "h1" : {
                "class" : "my-header"
            },
            "a" : {
                "class" : "my-a-class",
                "text" : "yahoo",
                "href" : "http://www.yahoo.com"
            }
        }];

        $(function() {
            $.each(widgets, function(i, item) {
                $('<div>').attr('id', item.div.id).html(
                $('<h1>').attr('class', item.h1.class).html(
                $('<a>').attr({
                    'href' : item.a.href,
                    'class' : item.a.class
                }).text(item.a.text))).appendTo('#container');
            });
        });
Luca Filosofi
  • 30,905
  • 9
  • 70
  • 77
  • Just for curious, what about the .html method performance ? Is it a good approach to implement with ? – ArunRaj Apr 10 '14 at 05:47
  • @ArunRaj: not sure what you mean, anyway, if you prefer you can use `$('#container').html($(''))` instead of `appendTo()`, but they are two different things, html will replace everything inside `#container` while appendTo just inject code in it. performance should be almost the same i guess. – Luca Filosofi Apr 10 '14 at 09:35
  • Sorry for putting up a question in a confusing way. But You answered my question what i have exactly meant. Thank you so much. – ArunRaj Apr 10 '14 at 09:42
9

This is the tidiest way to chain commands around your desired output:

var div_id = "my_div";
var h1_class = "my_header";
var a_class = "my_a_class";
var a_string = "teststring";

var new_div = $("<div>").attr("id",div_id).append(
    $("<h1>").addClass(h1_class).append(
        $("<a>").attr("href","/test/").addClass(a_class).text(a_string)
    )
);

$("div#container").append(new_div);

Not necessarily the most expedient, but certainly readable.

funwhilelost
  • 1,990
  • 17
  • 20
5

Use wrapInner() and wrap from inside out.

var div_id = "my_div",
    h1_class = "my_header",
    my_a_class = "my_a_class";

$('#container').wrapInner('<a href="/test/" class="' + my_a_class + '">'+a_string+'</a>').wrapInner('<h1 class="' + h1_class + '"/>').wrapInner('<div id="' + div_id + '"/>');

Check working example at http://jsfiddle.net/fWXYC/3/

Hussein
  • 42,480
  • 25
  • 113
  • 143
4
var template = '<div id="{my_div}">' + 
                    '<h1 class="{myclass}">' + 
                        '<a href="{url}" class="{my_a_class}">{a_string}</a>' + 
                    '</h1>' + 
               '</div>';

var content = {
    div_id: ["{my_div}","my_div"],
    h1_class: ["{myclass}","my_header"],
    a_class: ["{my_a_class}","my_a_class"],
    a_url: ["{url}", "http://www.google.com"],
    a_string: ["{a_string}","test string"]
}

$("#container").append(function (temp) {
    for(var i in content) {
            temp = temp.replace(new RegExp(content[i][0],'g'), content[i][1]);
    }

    return temp;
}(template));

Example: http://fiddle.jshell.net/yXFxQ/2/

bloodcell
  • 601
  • 1
  • 9
  • 23
Shaz
  • 15,637
  • 3
  • 41
  • 59
2
var $my_div = $('<div/>').attr('id', div_id);
var $h1 = $('<h1/>').addClass(h1_class);
var $a = $('<a/>').attr('href', '/test/').addClass(a_class).text(a_string);

$h1.append($a);
$my_div.append($h1);
$('#container').append($my_div);

http://jsfiddle.net/ALs6R/

gen_Eric
  • 223,194
  • 41
  • 299
  • 337
1
var div = $('<div>');
var div2 = $('<h1>');
var div3 = $('<a>');

div[0].id = "my_div";
div2[0].id = "my_header";
div3[0].class = "my_a_class";
div3.html("teststring");
$('#container').append(div.append(div2.append(div3)))
Naftali
  • 144,921
  • 39
  • 244
  • 303
0

It is more readable and maintainable if the JavaScript code resembles the HTML tag structure, similar to the way that Luca answered.

I have gone about this a bit differently and made a function to make each element an editable jQuery object.

For example:

$$('div', {'id':'container'},
    $$('div', {'id':'my_div'},
        $$('h1',{'class':'my_header'},
            $$('a',{'href':'/test/', 'class':'my_a_class'}, 'teststring'))));

Where the $$ function returns a jQuery object:

This makes the approach more flexible and you can add event handlers, data etc. to the nested jQuery objects using chaining quite easily.

For example:

$$('div', {'id':'container'},
    $$('div', {'id':'my_div'},
        $$('h1',{'class':'my_header'},
            $$('a', { 'href': '/test/', 'class': 'my_a_class' }, 'teststring')
        ).click(function() { alert('clicking on the header'); })
    ).data('data for the div')
).hide();

You probably don't want to overdo it, but I still find the code more readable than if one were to use the best practice jQuery approach of doing it with separate calls to .append(), .text(), .html() etc. or by feeding the jQuery $ a concatenated HTML string.

Here is the reference $$ function (you can call it something else if you don't like it, but I thought $$ is appropriate since it returns a jQuery object and it is also short):

function $$(tagName, attrTextOrElems) {
    // Get the arguments coming after the params argument
    var children = [];
    for (var _i = 0; _i < (arguments.length - 2) ; _i++) {
        children[_i] = arguments[_i + 2];
    }

    // Quick way of creating a javascript element without JQuery parsing a string and creating the element
    var elem = document.createElement(tagName);
    var $elem = $(elem);

    // Add any text, nested jQuery elements or attributes
    if (attrTextOrElems) {
        if (typeof attrTextOrElems === "string") { // text
            var text = document.createTextNode(attrTextOrElems);
            elem.appendChild(text);
        }
        else if (attrTextOrElems instanceof jQuery) { // JQuery elem
            $elem.append(attrTextOrElems);
        }
        else // Otherwise an object specifying attributes e.g. { 'class': 'someClass' }
        {
            for (var key in attrTextOrElems) {
                var val = attrTextOrElems[key];
                if (val) {
                    elem.setAttribute(key, val);
                }
            }
        }
    }

    // Add any further child elements or text    
    if (children) {
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            if (typeof child === "string") { // text
                var text = document.createTextNode(child);
                elem.appendChild(text);
            } else { // JQuery elem
                $elem.append(child);
            }
        }
    }
    return $elem;
}
Http.Code.301
  • 51
  • 1
  • 2
0

Use jQuerys wrap() method.

James South
  • 10,147
  • 4
  • 59
  • 115
-1
$('#container').html('<div id="'+div_id+'">
        <h1 class="'+my_header+'">
            <a href="/test/" class="'+my_a_class+'">'+teststring+'</a>
        </h1>
    </div>');

Try this?

vertazzar
  • 1,053
  • 7
  • 10