Hide div that contains specific text - javascript

I want to hide a div based on the text inside. In the example below I want to hide the ones with "Handtekening" and the one with "Thuis". I prefer to do that with CSS. Is that possible?
The class names of the divs have to be the same...
<div class="test">
Pakket
</div>
<div class="test">
Handtekening
</div>
<div class="test">
Thuis
</div>
If not possible with CSS, how can it be done with JavaScript?

Here's an easy vanilla Javascript solution:
const divs = document.getElementsByClassName('test');
for (let x = 0; x < divs.length; x++) {
const div = divs[x];
const content = div.textContent.trim();
if (content == 'Handtekening' || content == 'Thuis') {
div.style.display = 'none';
}
}
Working JSFiddle here
Remember to include the script at the end of your HTML page (right before the </body> tag).

If you have control over the HTML output and have no problems with the text document getting twice as big, you can duplicate the content of each of those divs. Otherwise JavaScript is the way to go. Here is the CSS solution:
<div class="test" content="Pakket">
Pakket
</div>
<div class="test" content="Handtekening">
Handtekening
</div>
<div class="test" content="Thuis">
Thuis
</div>
Then use the selector for an attribute containing a string:
div[content~=Thuis] { display:none; }
The one above will match when "Thuis" is contained in the text as a separate word. If you want to match any occurrence of the string, you should use:
div[content*=and] { display:none; }

No, it won't be possible with pure CSS. You need to use JavaScript to do it.
This is code you can use for that:
var divs = document.querySelectorAll(".test");
Array.from(divs).forEach(function(div) {
if (div.textContent.indexOf("Handtekening") >= 0 || div.textContent.indexOf("Thuis") >= 0) {
div.style.display = "none";
}
});
var divs = document.querySelectorAll(".test");
Array.from(divs).forEach(function(div) {
if (div.textContent.indexOf("Handtekening") >= 0 || div.textContent.indexOf("Thuis") >= 0) {
div.style.display = "none";
}
});
<div class="test">
Pakket
</div>
<div class="test">
Handtekening
</div>
<div class="test">
Thuis
</div>

Here's one more solution:
Array.from( document.querySelectorAll('div.test') )
.filter( node => /\b(Handtekening|Thuis)\b/i.test(node.textContent) )
.forEach( node => node.style.display = 'none' );
<div class="test">
Pakket
</div>
<div class="test">
HANDTEKENING
</div>
<div class="test">
Test thuis blah blah
</div>
The main difference from chsdk's solution is that I'm using a single regexp test instead of multiple .indexOf() calls. IMO this is cleaner, more flexible and possibly more efficient as well.
The \b anchors in the regexp match word boundaries, so that e.g. "Thuis test" is matched but "Thuistest" is not. I suspect this is what the OP wants, but if not, the \b anchors can easily be removed and/or replaced with something else. For example, the regexp:
/^\s*(Handtekening|Thuis)\b/i
would match only if the words "Handtekening" or "Thuis" occur at the beginning of the content (possibly after some whitespace). Replacing the second \b with \s*$ would also require there to be nothing (except possibly whitespace) after the matched word.
The i flag at the end of the regexp literal makes the matching case-insensitive. If not desired, the i can simply be removed. I wanted to include it for illustrative purposes, though.
Ps. Some older browsers (such as, notably, Internet Explorer) may not support the ES6 arrow functions and the Array.from() method used in the code above. If compatibility with such old browsers is desired, here's an alternative implementation free from any such newfangled stuff:
var nodes = document.querySelectorAll('div.test');
for (var i = 0; i < nodes.length; i++) {
if ( /\b(Handtekening|Thuis)\b/i.test(nodes[i].textContent) ) {
nodes[i].style.display = 'none';
}
}
<div class="test">
Pakket
</div>
<div class="test">
HANDTEKENING
</div>
<div class="test">
Test thuis blah blah
</div>
AFAICT, this should be compatible with IE down to version 9, and of course with all modern browsers as well.

You could do the easy thing of hiding the elements with a second class.
So let's say we'll add the class="hidden".
See the example below:
.test {
color: blue;
}
.hidden {
display: none;
/* or visibility: hidden; */
}
<div class="test">
Pakket
</div>
<div class="test hidden">
Handtekening
</div>
<div class="test hidden">
Thuis
</div>
By adding the second class we're able to make a selection of which <div> element you'd like to show and which not.

To select elements based on text you can use js and check if text is equal to ones you want to hide. If it is you can set display property to none to hide that element.
[...document.querySelectorAll('.test')].forEach(function(e) {
if (['Handtekening', 'Thuis'].includes(e.textContent.trim())) {
e.style.display = 'none'
}
})
<div class="test">
Pakket
</div>
<div class="test">
Handtekening
</div>
<div class="test">
Thuis
</div>

You can do it just like this,
let filteredOut = ['Handtekening', 'Thuis'];
Array.from(document.querySelectorAll(".test")).forEach((elm) => {
if(filteredOut.includes(elm.textContent.trim())) elm.style.display = "none";
});
DEMO
Collect the values that are needs to be filtered out in a separate array.
Iterate over all the elements and check its value presents in the filter array.
If it exists, just hide it.
Side Note: You can use a class to add to the caught elements instead of inserting inline styles.

With CSS 3: no
With JavaScript: yes
With XPath: yes (something like //div[contains(text(),'Handtekening')]/.)
You can test your XPath here.

You can do it with JavaScript:
var elements = document.getElementsByClassName('test');
for(var i = 0; i<elements.length; i++){
if(elements[i].innerText==='Handtekening' || elements[i].innerText==='Thuis'){
elements[i].style.display = 'none';
}
}
<div class="test">
Pakket
</div>
<div class="test">
Handtekening
</div>
<div class="test">
Thuis
</div>

Here's pure JavaScript solution:
// Define your variables
var objectsToCheck = document.getElementsByClassName("test");
var hideText = "Pakket";
// Loop through your div objects
[].forEach.call(objectsToCheck, function (o) {
// Check if text appears in div under class "test"
if(o.innerText.toLowerCase() == hideText.toLowerCase()){
o.style.display = "none";
}
});

You can use querySelector to fetch elements and use element.classList.toggle to add/remove a class that will hide the value.
document.querySelector('#btn').addEventListener('click', function(){
var text = document.querySelector('#txt').value.trim();
var list = document.querySelectorAll('.test');
for(var i = 0; i< list.length; i++) {
list[i].classList.toggle('hide', list[i].textContent.trim() === text);
}
})
.hide {
display: none;
}
<div class="test">
Pakket
</div>
<div class="test">
Handtekening
</div>
<div class="test">
Thuis
</div>
<input type='text' id='txt' />
<button id='btn'>Hide Div</button>

You also have jQuery that makes this easy if you already use this
library: contains(text).
text: A string of text to look for. It's case sensitive.
The matching text can appear directly within the selected element, in any of that element's descendants, or a combination thereof. As with attribute value selectors, text inside the parentheses of :contains() can be written as a bare word or surrounded by quotation marks. The text must have matching case to be selected.
$( ".test:contains('Thuis'),.test:contains('Handtekening')" ).css( "display", "none" );
https://codepen.io/gc-nomade/pen/zEMbLz

Related

Is there a way to create an array of an element that contains a specific CSS style?

I'm trying to capture the elements that do not contain a display type of none.
let pfCard = document.getElementsByClassName("PortfolioCard").style.display = 'block';
This doesn't seem to be working as I believe it is attempting to modify the style type instead of retrieve it.
You can do this by getting all your elements by class name and then using filter on that list.
const blockElements = [...document.getElementsByClassName("PortfolioCard")].filter(x => x.style.display == "block");
console.log(blockElements.length);
<div class="PortfolioCard" style="display:block">block</div>
<div class="PortfolioCard">not block</div>
<div class="PortfolioCard" style="display:block">block</div>
You'd probably have to querySelectorAll(".PortfolioCard") to get an array of them, then .filter() the array looking for style.display != 'none'.
A nicer solution would be if you separate your display: none property into a small utility class like: .hide-portfolio { display: none; }, and hide them that way. Then you can search for them with querySelectorAll(".PortfolioCard:not(.hide-portfolio)");
Maybe this one?
console.log([...document.getElementsByClassName("PortfolioCard")].filter(item=> window.getComputedStyle(item).getPropertyValue('display') != "block"))
<div class='PortfolioCard' style='display:block'></div>
<div class="PortfolioCard" style="display:block"></div>
<div class="PortfolioCard" style='display:none'></div>
Or usearray.forEach:
let arr= [];
[...document.getElementsByClassName("PortfolioCard")].forEach(item=>{
if(window.getComputedStyle(item).getPropertyValue('display') != "block")
arr.push(item)
})
console.log(arr)
<div class='PortfolioCard' style='display:block'></div>
<div class="PortfolioCard" style="display:block"></div>
<div class="PortfolioCard" style='display:none'></div>

Having issue with DOM selection in jquery

<div class="wrapper">
<p class="text"></p>
</div>
<div class="wrapper">
<p class="text"></p>
<img></img>
</div>
<div class="wrapper">
<p class="text"></p>
<div class="vid"></div>
</div>
Assume above is a list of users' post, and I want to identify type of post of them. To select the image or video type is easy, for example the video, just select like $('.wrapper .vid').
But there is a problem when I want to select plaintext type of post, because the class text also appear in vid and image type of post.
Looks like you want wrapper elements which does not hae vid or img then
$('.wrapper').not(':has(img, .vid)')
If you want the text elements within them
$('.wrapper').not(':has(img, .vid)').find('.text')
You can use filter to get the three different types of posts. Something like this:
var $textPosts = $('.wrapper').filter(function() {
return $(this).find('img, .vid').length == 0;
});
var $imgPosts = $('.wrapper').filter(function() {
return $(this).find('img').length > 0;
});
var $vidPosts = $('.wrapper').filter(function() {
return $(this).find('.vid').length > 0;
});
Also note that the img HTML tag is self closing, eg:
<img src="foo.jpg" title="Foo" />
If i get this right that you want to get all the test in <p> with the class text, then you can do something like this
$('.wrapper > .text').html()
The above code will give you the content of only those element with class "text" that are direct under class "wrapper"
You can use .filter() to filter out the element with class text whose has no sibling:
var text = $('.text').filter(function() {
return $(this).siblings('*').length == 0
}).text();
Fiddle Demo
You can use
$('.wrapper p.text').text()
fiddle demo

Append HTML inside nested classes

I'm trying to use jQuery to loop through classes and append some text to an HTML element. I'm working with the following HTML (example case):
<div class="question">
<div class="title">
<strong>Here's the question title.</strong>
</div>
<div class="choice">Here's choice1.</div>
<div class="choice">Here's choice2.</div>
</div>
<div class="question">
<div class="title">
<strong>Here's the question title.</strong>
</div>
<div class="choice">Here's choice1.</div>
<div class="choice">Here's choice2.</div>
</div>
So what I'm trying to do is loop through each question on the page, see if the title matches some string, then append some text based on that statement. I have the following:
$('.question').each(function() {
var title = $(this).find('.title').innerHTML;
$('.choice').each(function() {
var span = document.createElement("span");
if (title == "someString")
{
span.className = "someClass";
}
else
{
span.className = "someOtherClass";
}
var text = document.createTextNode("text");
span.appendChild(text);
$(this).appendChild(span);
});
// put this in to see if outer loop was working
document.body.style.backgroundColor = "orange";
});
The text will change color based on what the title is, hence the different CSS classes. But it doesn't seem to be doing anything, not even appending the text to each choice. The background color does change to orange, and Chrome isn't throwing any errors from the script in the developer tools, so I'm totally lost. Can anyone help?
You can get the title like this:
var title = $(this).find('.title strong').text();
Here you're confusing jquery with native javascript, $(this) is a jquery object so you cannot use appendChild() here's how you change that:
$(this).get(0).appendChild(span);
Or you can use jQuery directly:
$(this).append(span);
Using Arun P Johny's fiddle, I've updated a few things;
FIDDLE
The following are the important changes;
var title = $.trim($(this).find('.title').text());
$(this).find('.choice').each(function () {...
Changing $('.choice') to $(this).find('.choice') because you only want to change the elements within that question, not every choice element on the page.
and find('.title').innerHTML; to find('.title').text()); because you only want to match the text within that div, not the html as well.
Something like this?:
Jsfiddle
jQuery ( Comment free code in the jsfiddle ):
// On document ready...
$(function () {
// Geat each title element...
$('.title').each(function () {
// Points to each title element as defined above
var title = $(this),
// Get all siblings of title element(s)
choices = title.siblings(),
// Ternary if statement. Equivalent to if ( X ) {} else {}
myClass = title.text().trim() === "Here's the question title." ? "someClass" : "someOtherClass";
// Make a span element...
$('<span />', {
class: myClass, // Give it a class
text: " Appended text" // Give it some text
}).appendTo(choices); // Append the span to each .choice element
});
});
Html:
<div class="question">
<div class="title"><strong>Here's the question title.</strong></div>
<div class="choice">Here's choice1.</div>
<div class="choice">Here's choice2.</div>
</div>
<div class="question">
<div class="title"><strong>Here's the question title.</strong></div>
<div class="choice">Here's choice1.</div>
<div class="choice">Here's choice2.</div>
</div>
<div class="question">
<div class="title"><strong>Here's title.</strong></div>
<div class="choice">Here's choice1.</div>
<div class="choice">Here's choice2.</div>
</div>
Css:
.someClass {
color: red;
}
.someOtherClass {
color: green;
}
.question { margin: 10px 0px; }

Javascript onmouseover and onmouseout

You can see in the headline what it is. I've four "div", and therein are each a p tag. When I go with the mouse on the first div, changes the "opacity" of the p tag of the first div. The problem is when I go on with the mouse on the second or third "div" only changes the tag "p" from the first "div". It should changes the their own "p" tags.
And it is important, that i cannot use CSS ":hover".
The problem is clear, it is that all have the same "id".
I need a javascript which does not individually enumerated all the different classes.
I' sorry for my english.
I hope you understand me.
My script:
<div onmouseout="normal();" onmouseover="hover();" >
<p id="something">LOLOL</p>
</div>
<div onmouseout="normal();" onmouseover="hover();" >
<p id="something">LOLOL</p>
</div>
<div onmouseout="normal();" onmouseover="hover();" >
<p id="something">LOLOL</p>
</div>
<div onmouseout="normal();" onmouseover="hover();" >
<p id="something">LOLOL</p>
</div>
Javascript:
function normal() {
var something = document.getElementById('something');
something.style.opacity = "0.5";
}
function hover() {
var something = document.getElementById('something');
something.style.opacity = "1";
CSS:
p {
opacity: 0.5;
color: red;
}
As Paul S. suggests, you need to pass this to the function so that it knows which element it has to work on.
<div onmouseout="normal(this);" onmouseover="hover(this);" >
<p>LOLOL</p>
</div>
<div onmouseout="normal(this);" onmouseover="hover(this);" >
<p>LOLOL</p>
</div>
<div onmouseout="normal(this);" onmouseover="hover(this);" >
<p>LOLOL</p>
</div>
<div onmouseout="normal(this);" onmouseover="hover(this);" >
<p>LOLOL</p>
</div>
And then select the child element <p> for the passed <div>. Here I select the first child p, i.e. the first element in the array of children of this element with tag p, that's why you see [0]. So if in each div you had two paragraph, then you could use e.g. getElementsByTagName("p")[1] to select the second <p>.
function normal(mydiv) {
mydiv.getElementsByTagName("p")[0].style.opacity="0.5";
}
function hover(mydiv) {
mydiv.getElementsByTagName("p")[0].style.opacity="1";
}
See the working example here: http://jsfiddle.net/mastazi/2REe5/
Your html should be something like this:
<div onmouseout="normal(1);" onmouseover="hover(1);">
<p id="something-1">LOLOL</p>
</div>
<div onmouseout="normal(2);" onmouseover="hover(2);">
<p id="something-2">LOLOL</p>
</div>
<div onmouseout="normal(3);" onmouseover="hover(3);">
<p id="something-3">LOLOL</p>
</div>
<div onmouseout="normal(4);" onmouseover="hover(4);">
<p id="something-4">LOLOL</p>
</div>
As you can see, we have different ids for your elements, and we pass the ids through the function that we trigger with onlouseover and onmouseout.
For your javascript, your code could be something like this:
function normal(id) {
var something = document.getElementById('something-'+id);
something.style.opacity = "0.5";
}
function hover(id) {
var something = document.getElementById('something-'+id);
something.style.opacity = "1";
}
For normal() and hover() we receive an id and change the style for the current element that have this id.
Please, check this JSFiddle that I've built for you.

hide parent div if child div is empty

Hod Do i hide the parent div EventsRollup if the child div RelatedEventsList is empty??
<div class="EventsRollup">
<span class="EventsRollupTitle">CPR & Health Safety Classes</span><br /><br/>
<div class="RelatedEventsList">
<!--EMPTY with a lot of whitespaces etc. but no text-->
</div>
</div><!--END EventsRollup-->
Why is this not doing it?
var listtext=$.trim($('.RelatedEventsList').text());
if (listtext===""){
$('.EventsRollup').hide();
}
.text() may return spaces and line breaks.
if (!/\S/.test(listtext)){
$('.EventsRollup').hide();
}
What you have should work fine, although i usually do the following
var listtext=$.trim($('.RelatedEventsList').text());
if (listtext.length === 0){
$('.EventsRollup').hide();
}
Try using the html() function:
var listText = $.trim($('.RelatedEventsList').html());
if(listText == '') {
$('.EventsRollup').hide;
}

Categories

Resources