How do I create these nested dom elements with jquery?
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?
UPDATED
- DEMO: http://so.lucafilosofi.com/how-do-i-create-these-nested-dom-elements-with-jquery/
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');
});
});
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.
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/
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/
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/
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)))
Use jQuerys wrap() method.
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;
}
$('#container').html('<div id="'+div_id+'">
<h1 class="'+my_header+'">
<a href="/test/" class="'+my_a_class+'">'+teststring+'</a>
</h1>
</div>');
Try this?
精彩评论