22

Imagine that I have something like the following (modified from http://viralpatel.net/blogs/jquery-get-text-element-without-child-element/)

<div id="foo">
    first
    <div id="bar1">
        jumps over a lazy dog!
    </div>
    second
    <div id="bar2">
        another jumps over a lazy dog!
    </div>
    third
</div>

How can I remove just (only text) "first", "second" and "third" from DOM without affecting any of the child elements.

Florent
  • 12,310
  • 10
  • 49
  • 58
user203687
  • 6,875
  • 12
  • 53
  • 85
  • http://stackoverflow.com/questions/2715167/jquery-how-to-remove-the-text-but-not-the-children-elements or http://stackoverflow.com/questions/3442394/jquery-using-text-to-retrieve-only-text-not-nested-in-child-tags – kannix Jul 24 '12 at 14:59
  • it's answered here http://stackoverflow.com/questions/6388507/use-jquery-to-select-text-not-in-an-element – fan711 Jul 24 '12 at 15:02
  • The answers in all of the linked questions are all either completely wrong, cause unwanted issues such as lost event handlers, or break in certain browsers (e.g. use of `nodeType` constants). – James Allardice Jul 24 '12 at 15:27

4 Answers4

32

If you want to remove all child text nodes you can use .contents() and then .filter() to reduce the matched set to only text nodes:

$("#foo").contents().filter(function () {
     return this.nodeType === 3; 
}).remove();​​​​​​​

Here's a working example.

Note: This will preserve any existing event handlers on the child elements, which answers using .html() will not do (since the elements are removed from the DOM and added back in).

Note 2: Answers in some of the linked questions show similar code to that in my answer here, but they use the nodeType constants (e.g. return this.nodeType === Node.TEXT_NODE). This is bad practice since IE below version 9 does not implement the Node property. It's safer to use the integers (which can be found in the DOM level 2 spec).

James Allardice
  • 164,175
  • 21
  • 332
  • 312
  • The terrible `.html` solutions don't remove handlers in this case (or maybe they do?), but that's just by accident because `.html` can insert nodes too (undocumented, though). Edit: Ok they definitely do remove handlers because of the implicit `.empty()` in `.html` – Esailija Jul 24 '12 at 15:07
  • @Esailija - Using the code from mgraph's answer seems to remove the event handler: http://jsfiddle.net/jamesallardice/PXxC4/1/ – James Allardice Jul 24 '12 at 15:08
  • so what does the 3 actually refer to? looking over the Dom level 2 spec i don't see nodetypes listed in any way by numbers. and i'm curious :) – Jamie Hutber Jul 24 '12 at 15:36
  • @JamieHutber - They are listed with numbers. See [this section](http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247). Looks like my link got messed up so it links to some random other part of the doc. – James Allardice Jul 24 '12 at 15:37
  • argh brilliant, thanks. Ye this is very interesting way of handling elements. I'll certainly be looking at ways i can use this. Cheers – Jamie Hutber Jul 24 '12 at 15:38
  • 2
    If you get an ILLEGAL error in your browser(esp. WebKit) then look at the accepted answer to this question for your answer: http://stackoverflow.com/questions/4404526/unexpected-token-illegal-in-webkit – Serj Sagan Jul 10 '13 at 20:07
13

Here's a non-jQuery version which works in all major browsers back to IE 5, just to demonstrate how unscary life without jQuery is.

Demo: http://jsfiddle.net/timdown/aHW9J/

Code:

var el = document.getElementById("foo"), child = el.firstChild, nextChild;

while (child) {
    nextChild = child.nextSibling;
    if (child.nodeType == 3) {
        el.removeChild(child);
    }
    child = nextChild;
}
Tim Down
  • 318,141
  • 75
  • 454
  • 536
7

try this :

$("#foo").html($("#foo").find("div"));​

demo : http://jsfiddle.net/PXxC4/

mgraph
  • 15,238
  • 4
  • 41
  • 75
4

You could use this.

$("#foo").html($("#foo").children());​
xdazz
  • 158,678
  • 38
  • 247
  • 274