Reputation: 1353
Let's say:
<div>
pre text
<div class="remove-just-this">
<p>child foo</p>
<p>child bar</p>
nested text
</div>
post text
</div>
to this:
<div>
pre text
<p>child foo</p>
<p>child bar</p>
nested text
post text
</div>
I've been figuring out using Mootools, jQuery and even (raw) JavaScript, but couldn't get the idea how to do this.
Upvotes: 106
Views: 78371
Reputation: 1
The solution with replaceWith only works when there is one matching element. When there are more matching elements use this:
$(".remove-just-this").contents().unwrap();
Upvotes: 0
Reputation: 2277
Replace div with its contents:
const wrapper = document.querySelector('.remove-just-this');
wrapper.outerHTML = wrapper.innerHTML;
<div>
pre text
<div class="remove-just-this">
<p>child foo</p>
<p>child bar</p>
nested text
</div>
post text
</div>
Upvotes: 8
Reputation: 63519
You should make sure to do this with the DOM, not innerHTML
(and if using the jQuery solution provided by jk, make sure that it moves the DOM nodes rather than using innerHTML
internally), in order to preserve things like event handlers.
My answer is a lot like insin's, but will perform better for large structures (appending each node separately can be taxing on redraws where CSS has to be reapplied for each appendChild
; with a DocumentFragment
, this only occurs once as it is not made visible until after its children are all appended and it is added to the document).
var fragment = document.createDocumentFragment();
while(element.firstChild) {
fragment.appendChild(element.firstChild);
}
element.parentNode.replaceChild(fragment, element);
Upvotes: 37
Reputation: 47127
Use modern JS!
const node = document.getElementsByClassName('.remove-just-this')[0];
node.replaceWith(...node.childNodes); // or node.children, if you don't want textNodes
oldNode.replaceWith(newNode)
is valid ES5
...array
is the spread operator, passing each array element as a parameter
Upvotes: 22
Reputation: 552
If you are dealing with multiple rows, as it was in my use case you are probably better off with something along these lines:
$(".card_row").each(function(){
var cnt = $(this).contents();
$(this).replaceWith(cnt);
});
Upvotes: 0
Reputation: 494
I was looking for the best answer performance-wise while working on an important DOM.
eyelidlessness's answer was pointing out that using javascript the performances would be best.
I've made the following execution time tests on 5,000 lines and 400,000 characters with a complexe DOM composition inside the section to remove. I'm using an ID instead of a class for convenient reason when using javascript.
Using $.unwrap()
$('#remove-just-this').contents().unwrap();
201.237ms
Using $.replaceWith()
var cnt = $("#remove-just-this").contents();
$("#remove-just-this").replaceWith(cnt);
156.983ms
Using DocumentFragment in javascript
var element = document.getElementById('remove-just-this');
var fragment = document.createDocumentFragment();
while(element.firstChild) {
fragment.appendChild(element.firstChild);
}
element.parentNode.replaceChild(fragment, element);
147.211ms
Conclusion
Performance-wise, even on a relatively big DOM structure, the difference between using jQuery and javascript is not huge. Surprisingly $.unwrap()
is most costly than $.replaceWith()
.
The tests have been done with jQuery 1.12.4.
Upvotes: 3
Reputation: 6468
Using jQuery you can do this:
var cnt = $(".remove-just-this").contents();
$(".remove-just-this").replaceWith(cnt);
Quick links to the documentation:
Upvotes: 145
Reputation: 259
if you'd like to do this same thing in pyjamas, here's how it's done. it works great (thank you to eyelidness). i've been able to make a proper rich text editor which properly does styles without messing up, thanks to this.
def remove_node(doc, element):
""" removes a specific node, adding its children in its place
"""
fragment = doc.createDocumentFragment()
while element.firstChild:
fragment.appendChild(element.firstChild)
parent = element.parentNode
parent.insertBefore(fragment, element)
parent.removeChild(element)
Upvotes: 0
Reputation: 24462
And, since you tried in mootools as well, here's the solution in mootools.
var children = $('remove-just-this').getChildren();
children.replaces($('remove-just-this');
Note that's totally untested, but I have worked with mootools before and it should work.
http://mootools.net/docs/Element/Element#Element:getChildren
http://mootools.net/docs/Element/Element#Element:replaces
Upvotes: 2
Reputation: 62793
The library-independent method is to insert all child nodes of the element to be removed before itself (which implicitly removes them from their old position), before you remove it:
while (nodeToBeRemoved.firstChild)
{
nodeToBeRemoved.parentNode.insertBefore(nodeToBeRemoved.firstChild,
nodeToBeRemoved);
}
nodeToBeRemoved.parentNode.removeChild(nodeToBeRemoved);
This will move all child nodes to the correct place in the right order.
Upvotes: 40
Reputation: 5100
Whichever library you are using you have to clone the inner div before removing the outer div from the DOM. Then you have to add the cloned inner div to the place in the DOM where the outer div was. So the steps are:
innerHTML
of the inner div to a variable or you can copy the inner tree recursively node by node.removeChild
on the outer div's parent with the outer div as the argument.Some libraries will do some or all of this for you but something like the above will be going on under the hood.
Upvotes: 2