cheeaun
cheeaun

Reputation: 1353

How to remove only the parent element and not its child elements in JavaScript?

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

Answers (13)

Franck
Franck

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

Johannes Buchholz
Johannes Buchholz

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

eyelidlessness
eyelidlessness

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

Gibolt
Gibolt

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

LaurensVijnck
LaurensVijnck

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

maxime_039
maxime_039

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

yunda
yunda

Reputation: 420

More elegant way is

$('.remove-just-this').contents().unwrap();

Upvotes: 29

jk.
jk.

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

user362834
user362834

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

campino2k
campino2k

Reputation: 1661

 $('.remove-just-this > *').unwrap()

Upvotes: 30

TJ L
TJ L

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

Jonny Buchanan
Jonny Buchanan

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

domgblackwell
domgblackwell

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:

  1. Save a reference to the outer div's parent in a variable
  2. Copy the inner div to another variable. This can be done in a quick and dirty way by saving the innerHTML of the inner div to a variable or you can copy the inner tree recursively node by node.
  3. Call removeChild on the outer div's parent with the outer div as the argument.
  4. Insert the copied inner content to the outer div's parent in the correct position.

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

Related Questions