Search code examples
javascriptjqueryinnertext

Need jQuery text() function to ignore hidden elements


I have a div set up something like this:

<div id="test"> <p>Hello</p> <p style="display: none">Goodbye</p> </div>

EDIT: To clarify, this is the simplest example. The div could have any arbitrary number of n deep nested children.

$('#test').getText() returns 'Hello Goodbye'. Here's a one liner to test in Firebug: jQuery('<div id="test"> <p>Hello</p> <p style="display: none">Goodbye</p> </div>').text()

This seems to be because what jQuery uses internally, textContent (for non IE), returns hidden elements as part of the text. Hrmph.

Is there a way to return the text content ignoring display:none'd elements? Basically I am trying to mimic the text you would get from highlighting the div with your mouse and copying to system clipboard. That ignores hidden text.

Interestingly, if you create a selection range and get the text from it, that also returns text inside display:none elements.

var range = document.body.createTextRange();
range.moveToElementText($('#test')[0]);
range.select();

console.log(range.toString()); // Also logs Hello Goodbye!

So creating a document selection range doesn't appear to do the same thing as highlighting with the mouse in terms of display:none elements. How do I get around this dirty pickle conundrum?

Edit: using .filter(':visible').text has been suggested, but it won't work for this scenario. I need the returned text to be EXACTLY what would come from a selection with the mouse. So for example:

$('<div>test1 <p>test2</p>\r\n <b>test3</b> <span style="display:none">none</span></div>').appendTo(document.body).children().filter(':visible').text()

returns

"test2test3"

When the output I actually want is

test1 test2
 test3

linebreaks, whitespace and all, which come from the \r\n


Solution

  • Filter the elements using .filter(":visible").

    Or use this:

    $("#test :visible").text();
    

    But the jQuery documentation advises us to use .filter() instead:

    Because :visible is a jQuery extension and not part of the CSS specification, queries using :visible cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. To achieve the best performance when using :visible to select elements, first select the elements using a pure CSS selector, then use .filter(":visible").