Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the innerText of an element, but exclude hidden children

How can I get text from a node so that it returns it with whitespace formatting like "innerText" does, but excludes descendant nodes that are hidden (style display:none)?

like image 988
Chris Avatar asked Nov 14 '13 18:11

Chris


2 Answers

UPDATE: As the OP points out in comments below, even though MDN clearly states that IE introduced innerText to exclude hidden content, testing in IE indicates that is not the case. To summarize:

  • Chrome: innerText returns text only from visible elements.
  • IE: innerText returns all text, regardless of the element's visibility.
  • Firefox: innerText is undefined (as indicated by the W3C, and in my testing).

Add all of this up, and you have a property to avoid like the plague. Read on for the solution....

If you want cross-browser compatibility, you'll have to roll your own function. Here's one that works well:

function getVisibleText( node ) {
    if( node.nodeType === Node.TEXT_NODE ) return node.textContent;
    var style = getComputedStyle( node );
    if( style && style.display === 'none' ) return '';
    var text = '';
    for( var i=0; i<node.childNodes.length; i++ ) 
        text += getVisibleText( node.childNodes[i] );
    return text;
}

If you want to get painfully clever, you can create a property on the Node object so that this feels more "natural". At first I thought this would be a clever way to polyfill the innerText property on Firefox, but that property is not created as a property on the Node object prototype, so you would really be playing with fire there. However, you can create a new property, say textContentVisible:

Object.defineProperty( Node.prototype, 'textContentVisible', {
    get: function() { 
       return getVisibleText( this );
    }, 
    enumerable: true
});

Here's a JsFiddle demonstrating these techniques: http://jsfiddle.net/8S82d/

like image 128
Ethan Brown Avatar answered Sep 29 '22 18:09

Ethan Brown


This is interesting, I came here because I was looking for why the text of display:none elements was omitted in Chrome.

So, this was ultimately my solution.
Basically, I clone the node and remove the classes/styling that set display:none.

How to add hidden element's innerText

function getInnerText(selector) {
    let d = document.createElement('div')
    d.innerHTML = document.querySelector(selector).innerHTML.replaceAll(' class="hidden"', '')
    return d.innerText
}
like image 41
Qwerty Avatar answered Sep 29 '22 20:09

Qwerty