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?

1
  • 4
    I love all the different ways to do this. :-D Commented Mar 15, 2011 at 22:16

9 Answers 9

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');
            });
        });
Sign up to request clarification or add additional context in comments.

3 Comments

Just for curious, what about the .html method performance ? Is it a good approach to implement with ?
@ArunRaj: not sure what you mean, anyway, if you prefer you can use $('#container').html($('</div>')) 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.
Sorry for putting up a question in a confusing way. But You answered my question what i have exactly meant. Thank you so much.
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.

Comments

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/

Comments

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/

Comments

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/

Comments

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)))

Comments

0

Use jQuerys wrap() method.

Comments

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;
}

Comments

-1
$('#container').html('<div id="'+div_id+'">
        <h1 class="'+my_header+'">
            <a href="/test/" class="'+my_a_class+'">'+teststring+'</a>
        </h1>
    </div>');

Try this?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.