Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to hide an element, based on its text, with JavaScript?

Tags:

javascript

I'm a beginner developer. I'm trying to hide a div that is dynamically added to the page by a 3rd party JavaScript for aesthetic purposes.

The problem is that the div has no id attribute; is this even possible? Do divs have any inherent attributes based on the order in which they load? Or is there any way to search for a string of text and hide the element?

For example, removing <div>happy New year</div> based on its text happy New year.

like image 361
user3180 Avatar asked Dec 09 '12 08:12

user3180


3 Answers

You can select the relevant elements first and iterate through them until you find what you want.

In JQuery it can be done like this:

// select relevant elements
var elements = $('div');

// go through the elements and find the one with the value
elements.each(function(index, domElement) {
    var $element = $(domElement);

    // does the element have the text we're looking for?
    if ($element.text() === "happy New year") {
        $element.hide();
            // hide the element with jQuery
        return false; 
            // jump out of the each
    }
});

Note that the code is a bit brittle and completely depends on the contents of the elements. Here are the relevant JQuery api docs:

  • Selectors in jQuery ($(...))
  • jQuery.each() - for going through the jquery objects array
  • jQuery.text() - for getting the value (there are small but noticable discrepancies between the browsers on how you do this in plain javascript)
  • jQuery.hide() - for hiding the element with CSS style display: none

Note that you can be more specific with your selection say you have the following code:

<div class="message">
    <div>happy New year<div>
</div>

You can select the element with:

var domElement = $('.message div')[0]; // hopefully it only happens once
like image 195
Spoike Avatar answered Nov 03 '22 10:11

Spoike


I thought I'd offer a plain-JavaScript alternative, which could be improved (quite a bit), particularly the passing of Booleans as strings (which feels hideous):

function hideByText(text, opts) {
    if (!text) {
        return false;
    }
    else {
        var defaults = {
            // the element we look within, expects:
            // 1: node reference, eg the result of: document.getElementsByTagName('div')[0]
            // 2: an element's id, as a string, eg: 'test'
            'within': document.body,
            // the element type, eg 'div', 'span', 'p', defaults to *everything*
            'elemType': '*',
            // case-sensitivity, as a string:
            // 'true' : is case sensitive, 'Some' will not match 'some',
            // 'false' : is case insensitive, 'Some' will match 'some'
            'sensitive': 'true',
            // 'absolute' : 'some text' will not match 'some text.'
            // 'partial' : 'some text' will match 'some text.'
            'match': 'absolute',
            // 'true' : removes white-space from beginning, and end, of the text,
            // 'false' : does not remove white-space
            'trim': 'true',
            // the class to add to elements if a match is made,
            // use CSS to hide, or style, the matched elements
            'matchedClass': 'hasText'
        },
            opts = opts || {};

        for (var setting in defaults) {
            if (defaults.hasOwnProperty(setting)) {
                opts[setting] = opts[setting] || defaults[setting];
            }
        }

        var within = opts.within.nodeType == 1 ? opts.within : document.getElementById(opts.within),
            elems = within.getElementsByTagName(opts.elemType),
            flags = opts.sensitive == 'true' ? 'i' : '',
            needle = opts.trim == 'true' ? text.replace(/^(\s+) || (\s+)$/g, '') : text,
            haystack,
            reg = new RegExp(needle, flags);

        if (opts.match == 'absolute') {
            for (var i = 0, len = elems.length; i < len; i++) {
                if ((elems[i].textContent || elems[i].innerText) == text) {
                    elems[i].className = opts.matchedClass;
                }
            }
        }
        else if (opts.match == 'partial') {
            for (var i = 0, len = elems.length; i < len; i++) {
                if ((elems[i].textContent || elems[i].innerText).match(reg)) {
                    elems[i].className = opts.matchedClass;
                }
            }
        }
    }
}

hideByText('some text', {
    'match': 'partial',
    'sensitive': 'true',
    'elemType': 'p',
    'matchedClass' : 'hasText'
});​

JS Fiddle demo.

like image 3
David Thomas Avatar answered Nov 03 '22 10:11

David Thomas


A previous answer will hide a node based on the combined text content (see .text() behavior). The following test cases will illustrate this:

should stay: <div><em>happy New year</em></div><br>
should stay: <div>happy New years</div><br>
should stay: <div>happy New <em>year</em></div><br>
should stay: <div>Something else entirely</div><br>
should hide: <div>happy New year</div>

Shown here: jsFiddle

Depending on the details of your situation, this more general behavior may be what you want as it will ignore descendant structure and only match against the combined text. But, if you need to hide the <div> that specifically contains the text, something like the following will hide only the last <div> from the test cases:

var tx = 'happy New year';
$('div:contains(' + tx + ')').filter(function(){
    var $content = $(this).contents();
    return $content.length === 1 && 
        $content[0].nodeType === 3 &&
        $content.text() === tx;
}).hide();

Shown here: jsFiddle

The initial selector can be modified to hide anything that contains the specific text. This more general approach will hide the <em> element in the first case and the <div> element in the last case:

$(':contains(' + tx + ')').filter(// etc...

You might consider removing the element from the DOM instead of only hiding it.

:contains() jQuery selector

.filter() jQuery method

.contents() jQuery method

nodeType Node property

.remove() jQuery method

like image 1
tiffon Avatar answered Nov 03 '22 08:11

tiffon