6

I have some HTML like this:

<div>TEXT
    <span>SPAN</span>
        <a href="">LINK</a>
</div>

I would like to remove the contents of the elements, usually I would do something like this:

$('*').empty(); 

or

$('*').contents().empty();

This however will remove/empty the first span and its content which is the div and link. What can I do to preserve the elements while emptying them? So the end result would be:

<span>
    <div></div>
    <a href=""></a>
</span>

Please note I'm looking for something 'universal' that can be applied to any HTML. The above is just an example, in reality the HTML structure would contain more data.

Example at JsFiddle

Youss
  • 4,196
  • 12
  • 55
  • 109

4 Answers4

3

Recursively loop through all nodes, and remove all children whose nodeType property equals 3 (Node.TEXT_NODE). jQuery cannot select just text nodes, so this can be done using vanilla JavaScript.

Example:

function removeText(node) {
    if (!node || !node.childNodes || !node.childNodes.length) return;
    for (var i=node.childNodes.length-1; i>=0; --i) {
        var childNode = node.childNodes[i];
        if (childNode.nodeType === 3) node.removeChild(childNode);
        else if (childNode.nodeType === 1) removeText(childNode);
    }   
}

Or, packed in a jQuery plugin:

$.fn.removeText = function() {
    for (var i=this.length-1; i>=0; --i) removeText(this[i]);
    return this;
};

http://jsfiddle.net/hcKsX/

Rob W
  • 341,306
  • 83
  • 791
  • 678
  • 1
    @Youss I added a fiddle. It seems to work fine. Also with your example: http://jsfiddle.net/hcKsX/1/ – Rob W Mar 19 '13 at 21:26
  • Yes! it works:) Thank you very much. Does this only work for text..? Do you think it can be applied to other data like images? – Youss Mar 19 '13 at 21:33
  • @Youss Are you referring to the `alt` attribute? `$('img[alt]').attr('alt','');` – Rob W Mar 19 '13 at 21:34
  • @Rob W I actually was just referring to all sorts of data incuding images. But now that you put that way I'm starting to think its a completely different problem... – Youss Mar 19 '13 at 21:38
  • But I guess when it comes to images I can do event remove()..(??) – Youss Mar 19 '13 at 21:39
  • 1
    @Youss Yes. `$('img').remove();`. There are several kinds of nodes in DOM. Often, you're interested in manipulating elements, and occasionally text nodes. Other node types also exist, but you will probably not use these as often as the previous two types. See also: https://developer.mozilla.org/en-US/docs/DOM/Node.nodeType – Rob W Mar 19 '13 at 21:42
  • @Rob W I just tested remove() for the images and it seems the HTML structure is preserved. You are right, there was one question that was in the back of my mind the whole time; "what else is there apart from text and images...?" Anyway thanks for the link:) – Youss Mar 19 '13 at 21:46
2

Get the children of the parent item and set their html like thus:

$('#myspan').children().html('');

jsFiddle

Marcus
  • 5,407
  • 3
  • 31
  • 54
1

These solutions are all ok, but none of them satisfy your condition.

Example #1: remove all text inside leaf nodes

$('body *:not(:has(*))').empty()

result:

<span>SPAN
    <div></div>
    <a href=""></a>
</span>

Example #2: remove all text inside children of just one node

$('body span').children().html('')

result:

<span>SPAN
    <div></div>
    <a href=""></a>
</span>

(same as above). However, this solution would not work if there were more than 2 levels of nesting.

Other solutions have similar downfalls.

The real problem here is there's no good way to clear text out of a node that is both a parent node AND a text node. You should either hack something together or re-render your view each time.

Connor McArthur
  • 241
  • 2
  • 9
  • I understand you very clear:) At the moment I'm scraping bbc news. Using the codes in the anwsers so far does a lot of 'damage' to the HTML structure – Youss Mar 19 '13 at 21:22
0

This should remove all text nodes in a dom tree:

$('*').contents().filter(
  function() {
    return this.nodeType == 3;
}).remove();
acme
  • 14,654
  • 7
  • 75
  • 109