Reputation: 486
My HTML looks like this:
<div class='background'>
<div class='item' id='item1'>... </div>
<div class='item' id='item2'>... </div>
<div class='item' id='item3'>... </div>
... (more 'item's follow)
</div> <!-- background>
What I've been trying to accomplish, using jQuery, is to close the background
div before item2
, then reopen it again afterwards. Like this:
$('#item2').before('</div>');
$('#item2').after('<div class="background">');
But jQuery perversely insists on resolving this to:
<div class='background'>
<div class='item' id='item1'>... </div>
<div class="background"></div>
<div class='item' id='item2'>... </div>
<div class='item' id='item3'>... </div>
...
</div> <!-- background>
which is, obviously, useless.
In increasing desperation, I've tried using the .html()
method to force the </div>... <div>
tags to appear. No use: jQuery simply can't believe I want to insert that markup. (This tortured syntax:
var oldc = $('#item2').html();
var newc = '</div></div>'+oldc+'<div class="background"><div>';
$('#item2').html(newc);
resolves to:
<div class="item" id="item2">...
<div class="background"><div></div></div>
</div>
(as viewed in Firebug).)
Is there a simple way to resolve this using jQuery, or am I being fundamentally misguided?
To clarify: what I want to end up with is this:
<div class='background'>
<div class='item' id='item1'>... </div>
</div>
<div class='item' id='item2'>... </div>
<div class="background">
<div class='item' id='item3'>... </div>
... (more 'item's follow)
</div> <!-- background>
Upvotes: 0
Views: 960
Reputation: 707218
You can't just add close tags like that with DOM manipulation. You can create the new div you want, append it after the existing one and then move some DOM elements from the original background div to the new background div. You could do that with this code:
var newContainer = $("<div class='background'></div>");
$(".background").after(newContainer);
$("#item2").nextAll().appendTo(newContainer);
This creates the new background div, places it after the current background div, then gets all siblings after #item2
and moves them to the new background div.
Working Demo: http://jsfiddle.net/jfriend00/G3uyA/
OK, based on your clarification, this code will do the same as the above, but also pull item2 out to be at the same level as the background:
var origContainer = $(".background");
var target = $("#item2");
$("<div class='background'></div>").insertAfter(origContainer).append(target.nextAll());
target.insertAfter(origContainer);
Working Demo: http://jsfiddle.net/jfriend00/7Dsqw/
Upvotes: 3
Reputation: 17061
I think the most efficient way to do this would be to not have these elements contained in the .background
div by default.
Then, target all elements that come after #item1
and use wrapAll()
to wrap them with .background
:
$("#item1").nextAll().wrapAll( $("<div>").addClass("background") );
Then target #item1
and use wrap()
to wrap it in a second .background
element:
$("#item1").wrap( $("<div>").addClass("background") );
You can even chain them:
$("#item1")
.nextAll()
.wrapAll( $("<div>").addClass("background") )
.end()
.wrap( $("<div>").addClass("background") );
The reason we wrap the ones after #item1
first is because once #item1
is wrapped, using nextAll()
wouldn't give us anything since the rest of the elements would no longer be its siblings.
EDIT: After your clarification, I modified the above example slightly to not include #item2
in the nextAll()
. This way, #item1
will be placed in its own .background
element and anything after #item2
the same. #item2
will not be affected:
$("#item1")
.nextAll(":not(#item2)")
.wrapAll( $("<div>").addClass("background") )
.end()
.wrap( $("<div>").addClass("background") );
And finally, if you're not actually able to remove the original .background
from the existing HTML, you can use unwrap()
to remove the parent but leave all the children:
$("#item1")
.unwrap()
.nextAll(":not(#item2)")
.wrapAll( $("<div>").addClass("background") )
.end()
.wrap( $("<div>").addClass("background") );
Upvotes: 1