Hide element only if it contains specific text inside, using Java Script - javascript

I have these elements on my page:
<div id="123test"><p>test</p></div>
<div id="123test"><p>othertext</p></div>
And I am trying to remove the div if it contains "test" text inside, using Java Script, but it does not seem to work.
Here is my JS:
var container = document.getElementById('123test');
if (container.textContent=='test') {
container.style.display="none";
};
var container = document.getElementById('123test');
if (container.textContent == 'test') {
container.style.display = "none";
};
<div id="123test"><p>test</p></div>
<div id="123test"><p>othertext</p></div>
I also tried using :contains selector way, but the result was the same. The style of the container does not change at all. What do I do wrong? Is there another approach possible? This code is a simplified version of my project, but neither of these two work. I would be very gratefull if someone would help me to overcome the issue.

Make sure your HTML looks exactly like this:
<div id="123test"><p>test</p></div>
<!-- no whitespace or line breaks before or after <p>test</p> -->
and not like this
<div id="123test">
<p>test</p>
</div>
To avoid this problem, call trim() on container.textContent:
var container = document.getElementById('123test');
if (container.textContent.trim() == 'test') {
container.style.display = "none";
};
<div id="123test">
<p>test</p>
</div>
<div id="123test2">
<p>othertext</p>
</div>
And I am trying to remove the div if it contains "test" text inside, using Java Script [...]
If it is sufficient that test is contained, check for includes('test') instead:
var container = document.getElementById('123test');
if (container.textContent.includes('test')) {
container.style.display = "none";
};
<div id="123test">
<p>test123</p>
</div>
<div id="123test2">
<p>othertext</p>
</div>
Important sidenote: You cannot have more than one element with the same id.
Sidenote 2: :contains only exists in jQuery, not in CSS.
Sidenote 3 about using innerText: This had been my first approach, but for some strange reason on Safari/MacOS it won't hide the container:
var container = document.getElementById('123test');
if (container.innerText == 'test') {
container.style.display = "none";
};
console.log(container.innerText.length); // 6 (!) on Safari/MacOS
<div id="123test">
<p>test</p>
</div>
<div id="123test2">
<p>othertext</p>
</div>

Here is an example of checking an arbitrary DOM tree for text nodes that contain the string "test" and then hiding them by setting display: none;.
The function hideTestNodes accepts NodeList and primarily makes use of nodeType and textContent.
const wrapper = document.getElementById('wrapper')
const hideTestNodes = (children) => {
for (const child of children) {
if (child.nodeType === 1) {
// If the node is another Element, check its child nodes
hideTestNodes(child.childNodes)
}
// If the node is a text node and the content includes 'test'
// then hide the parent element containing the text node
if (child.nodeType === 3 && /test/i.test(child.textContent)) {
child.parentElement.style.display = 'none'
}
}
}
hideTestNodes(wrapper.childNodes)
<div id="wrapper">
<div>
<p>test</p>
</div>
<div>
<p>some other text</p>
</div>
<div>
<p>some deeply <span> nested test</span> text</p>
</div>
<div>
<p>this <span>includes</span> test.</p>
</div>
</div>

If you want to do that to only one specific div, then it's very simple:
NOTE: I added two seconds to let you see how it happens. you can remove the timer.
let test1 = document.getElementById("test1");
if (test1.innerHTML.includes("test")) {
setTimeout(() => {
test1.style.display = "none";
}, 2000);
}
<div id="container">
<div id="test1"><p>test</p></div>
<div id="test2"><p>othertext</p></div>
</div>
If you want to check all divs, it's still simple and you just need to make an array from them then use forEach loop to check all divs in that container:
let divs = document.getElementById("container").children;
[...divs].forEach(div => {
if (div.textContent.includes("test")) {
setTimeout(() => {
div.style.display = "none";
}, 2000);
}
});
<div id="container">
<div id="test1"><p>test</p></div>
<div id="test2"><p>othertext</p></div>
</div>

Related

Javascript click event doesn't work properly I can't give class

function getCountryByDiv(selectedCountry) {
x = document.getElementById("neighbors").children;
console.log(x);
for (let i of x){
console.log(i);
if(i.classList.contains("clicked")){
i.classList.remove("clicked");
}
else{
selectedCountry.classList.add("clicked");
console.log("evet");
}
}
htag = document.querySelector(".clicked .card-title");
console.log(htag);
getCountry(htag.innerText);
}
function renderNeighbors(data) {
console.log(data);
let html = "";
for (let country of data) {
html += `
<div onclick="getCountryByDiv(this)" class="col-2 mt-2">
<div class="card clickable">
<img src="${country.flags.png}" class="card-img-top">
<div class="card-body">
<h6 class="card-title">${country.name.common}</h6>
</div>
</div>
</div>
`;
}
document.querySelector("#neighbors").innerHTML = html;
}
Click event doesn't work properly and I don't know why. When I click to the last child it can't find innerText. But there is innerText. I can't see any problem but it still doesn't work. I can't give class to the last child (.clicked).
Error](https://i.stack.imgur.com/RFfqy.png)
But it has innerText](https://i.stack.imgur.com/DSCvX.png)
If you want I can send the whole code.
design](https://i.stack.imgur.com/62iVm.png)
I'm trying to give class to the last child and send the innerText of h6 to the function.
(English is not my native tounge so if I wrote anything wrong sorry about that.)
You have to add the "clicked" on the clicked div outside of the loop. You already pass the clicked elem as a parameter, so you can set it directly:
function getCountryByDiv(selectedCountry) {
x = document.getElementById("neighbors").children;
console.log(x);
for (let i of x){
console.log(i);
if(i.classList.contains("clicked")){
i.classList.remove("clicked");
}
}
// moved here
selectedCountry.classList.add("clicked");
htag = document.querySelector(".clicked .card-title");
console.log(htag);
getCountry(htag.innerText);
}
In the original code it failed on the last element because there was no following element which resetted the class "clicked" in the else-condition.

Hide div element after a few seconds Angular 7

So I am having trouble understanding how to do this and how to approach this issue... I have a scroll animation on my page and I want to hide that div with animation after 3 seconds when it comes into view.
My HTML code for animated element is:
<div class="scroll-animation-wrapper">
<div class="scroll-animation">
<span></span>
<span></span>
<span></span>
</div>
</div>
Code in my Typescript is:
hideAnimatedDiv() {
const animatedDiv = document.getElementsByClassName('scroll-animation');
this.animatedDiv = true;
setTimeout(() => {
console.log('hide');
this.animatedDiv = false;
}, 3000);
}
I keep getting this error:
ERROR in src/app/configurator/configurator.component.ts(577,14): error TS2339: Property 'animatedDiv' does not exist on type 'ConfiguratorComponent'.
src/app/configurator/configurator.component.ts(580,18): error TS2339: Property 'animatedDiv' does not exist on type 'ConfiguratorComponent'.
Your code is trying to find animatedDiv property as global, because you have used this.animatedDiv instead try like this.
HTML
<div class="scroll-animation-wrapper">
<div id="scroll-animation" class="scroll-animation">
<span>a</span>
<span>b</span>
<span>c</span>
</div>
</div>
TS
ngOnInit() {
this.hideAnimatedDiv()
}
hideAnimatedDiv() {
let animatedDiv = document.getElementById('scroll-animation');
animatedDiv.style.display = 'block';
setTimeout(() => {
console.log('hide');
animatedDiv.style.display = 'none';
}, 3000);
}
To hide any element, we need to use style.display property of that element, like shown in the code.
Note: I have used ngOnInit function to make sure that div is hidden after component load only.
If you want to hide div I would suggest you this:
<div class="scroll-animation-wrapper">
<div class="scroll-animation" *ngIf="isDisplayed">
<span></span>
<span></span>
<span></span>
</div>
</div>
As you can see I added " *ngIf="isDisplayed" ". You should add the property "isDisplayed" to the component.
public isDisplayed: boolean = true;
hideAnimatedDiv() {
setTimeout(() => {
this.isDisplayed = false;
}, 3000);
}
If you want to add animation in Angular, the best way is to implement it as Angular Team suggests:
With this specific case I would use ":enter" ":leave" approach: https://angular.io/guide/transition-and-triggers#use-of-ngif-and-ngfor-with-enter-and-leave

Find closest ancestor of a clicked element from given array

I'm trying to get the closest ancestor element to a clicked element, from an array of provided elements. When a user clicks on a tab, I need to find out where on the page that tab is.
I have something kind of working, however this script thinks main is the closest tag, when it should be article.
If I put article before main in the array it works just fine, however I want this to work regardless of array order. Any ideas?
// Tab Click
var tabs = Array.from(document.querySelectorAll('details.company-details'));
function handleTabClick(e) {
var tabNode = e.target;
tabLabel = tabNode.innerText;
const tgt = e.target;
var location;
var elements = ['section', 'header', 'main', 'nav', 'article'];
for (let element of elements) {
if (tgt.closest(element)) {
location = element;
break;
};
}
console.log(location);
};
tabs.forEach(function(tab) {
tab.addEventListener('click', handleTabClick);
});
<main class="company-main-wrapper" id="maincontent">
<article>
<div class="company-grid-row">
<div class="company-grid-column-two-thirds">
<div class="company-page-content">
<div class="block-expander">
<details class="company-details company-expander" company-polyfilled="true" id="company-details0" open="">
<summary class="company-details__summary" role="button" aria-controls="company-details__text0" tabindex="0" aria-expanded="true">
<span class="company-details__summary-text">
sampoe page
</span>
</summary>
</details>
</div>
</div>
</div>
</div>
</article>
</main>
See the comments inline below:
// Don't need Array.from() because the node list returned from
// .querySelectorAll() supports .forEach().
document.querySelectorAll('details.company-details').forEach(function(tab) {
tab.addEventListener('click', handleTabClick);
});
var elements = ['section', 'header', 'main', 'nav', 'article'];
let found = false;
let parent = null;
function handleTabClick(e) {
// Start at the parent of the tab
parent = this.parentNode;
// Keep looping until we find an ancestor that matches
while (found === false){
// Check the name of the parent element to see if its lower
// cased name is in the array.
if(elements.includes(parent.nodeName.toLowerCase())){
found = true; // Found a match
} else {
// No match. Get the next parent and keep looping
parent = getParent(parent);
}
}
console.log(parent);
};
function getParent(element){
return element.parentNode;
}
<main class="company-main-wrapper" id="maincontent">
<article>
<div class="company-grid-row">
<div class="company-grid-column-two-thirds">
<div class="company-page-content">
<div class="block-expander">
<details class="company-details company-expander" company-polyfilled="true" id="company-details0" open="">
<summary class="company-details__summary" role="button" aria-controls="company-details__text0" tabindex="0" aria-expanded="true">
<span class="company-details__summary-text">
sampoe page
</span>
</summary>
</details>
</div>
</div>
</div>
</div>
</article>
</main>

condition to check whether any element has a specific class

I have a javascript loop that contains a conditional statement.
I need the condition to check whether the current item in the loop contains any element with a specific class name.
This is what I currently have, however as you'll see this is not correct.
Currently my condition checks whether the current element has a specific class name, HOWEVER, I need it to check whether ANY element inside the element has a specific class name.
selectionList.forEach(selectionItem => {
if (selectionItem.classList.contains('myclass')) {
// do something
} else {
// do something different
}
}
EDIT:
I'm editing this post because it seems that people are misunderstanding.
I just need help with the following line in my code:
if (selectionItem.classList.contains('myclass')) {
The above checks whether the current element has a specific class name, but I need it to check whether the current element contains any CHILD element with a specific class name.
You can use .querySelector(selector) to search for children of some element.
!!element.querySelector(selector) will return true if it finds something matching selector inside that element, and will return false otherwise.
let elements = document.querySelectorAll('.outer');
elements.forEach(el => {
let hasChildren = !!el.querySelector('.searchClass');
console.log(`${el.classList[1]} has children with .searchClass: ${hasChildren}`);
});
<div class="outer outer-1">
<div class="inner searchClass"></div>
</div>
<div class="outer outer-2">
<div class="inner"></div>
</div>
<div class="outer outer-3">
<div class="inner">
<div class="inner searchClass"></div>
</div>
</div>
You can use Element.querySelector(selector) or either Element.querySelectorAll(selector).length in order to check if there is a child with the given selector:
yourElements.forEach(element => {
if (element.querySelector(yourSelector)) {
// do something
} else {
// do something different
}
})
// if there is no "something different" to do would be like this
yourElements.filter(elem => !!elem.querySelector(yourSelector))
.forEach(element => {
// do something
})
In your case could be something like
selectionList.forEach(selectionItem => {
if (selectionItem.querySelector('.myclass')) {
// do something
} else {
// do something different
}
})
Instead of a loop, just call .querySelectorAll() with the class name passed in (prefixed with a .) on the element you wish to examine to return a collection of all the elements that contain that class. You can check the resulting collection's .length to see how many elements were found and you can loop over the collection (with .forEach()) to enumerate them individually.
// Find every element that has the myclass class and put them in a collection
let matchingElements = document.querySelectorAll(".match");
let count = matchingElements.length; // Count how many there are
// Loop over the collection
matchingElements.forEach(function(element){
// Do whatever you want with the current element being enumerated
console.log(element.textContent);
});
<div class="needsChecking">
<p>something</p>
<p class="match">bingo</p>
stuff
<div>
<div class="match">bingo
<h1 class="match">bingo</h1>
<h2 class="nomatch"></h2>
</div>
</div>
<div class="needsChecking">
<p>something</p>
<p class="match">bingo</p>
stuff
<div>
<div class="match">bingo
<h1 class="match">bingo</h1>
<h2 class="nomatch"></h2>
</div>
</div>
<div class="needsChecking">
<p>something</p>
<p class="match">bingo</p>
stuff
<div>
<div class="match">bingo
<h1 class="match">bingo</h1>
<h2 class="nomatch"></h2>
</div>
</div>
You can use the children property.
See my snippet below, I've included some notes.
//get parent element
var parent = document.querySelector('.parent');
//get children
var children = parent.children;
//run a loop and check if children have a specific class name
for (let i = 0; i < children.length; i++) {
if (children[i].classList.contains('child1')) {
//log the children with class name child1
console.log(children[i])
}
}
<div class="parent">
<p class="child1"></p>
<p class="child1"></p>
<p class="child2"></p>
<p class="child3"></p>
</div>

sort dom elements on the basis of href attribute in JS

I have DOM elements as shown below. I want to sort it on the basis of href attribute.
This is what I have tried in JS but more need to be done.
document.addEventListener("DOMContentLoaded", function () {
let elems = Array.from(document.querySelectorAll(".house-senate a"));
elems.sort((a, b) => a.textContent.localeCompare(b.textContent));
});
Problem Statement:
I am wondering what JS code I need to add so that it sorts everything on the basis of href attributes.
You're close, but:
You need to actually move them in the DOM.
You're potentially sorting ones that aren't in the same parent (though they all are in your example HTML).
blex pointed out to me that you want to sort by the category in the href, not by the href itself. In your example, it comes to the same thing because the text prior to the category in all the hrefs is the same, but still, perhaps better to extract it.
This is blex's function for extracting it:
function getLinkCategory(a) {
const matches = a.href.match(/category=([a-z]+)/i);
return matches ? matches[1] : '';
}
Or if you want to be more rigorous about extracting that parameter from the query string, this collaborative answer originally by Code Spy shows how to do that.
See comments for more:
document.addEventListener("DOMContentLoaded", function () {
// Get the container
const container = document.querySelector(".house-senate");
// Get its immediate child `a` elements
const elems = [...container.children].filter(child => child.tagName === "A");
// Sort them
elems.sort((a, b) => getLinkCategory(a).localeCompare(getLinkCategory(b)));
// Add them back, which moves them
for (const el of elems) {
container.appendChild(el);
}
});
Live Example:
function getLinkCategory(a) {
const matches = a.href.match(/category=([a-z]+)/i);
return matches ? matches[1] : '';
}
document.addEventListener("DOMContentLoaded", function () {
// Get the container
const container = document.querySelector(".house-senate");
// Get its immediate child `a` elements
const elems = [...container.children].filter(child => child.tagName === "A");
// Sort them
elems.sort((a, b) => getLinkCategory(a).localeCompare(getLinkCategory(b)));
// Add them back, which moves them
for (const el of elems) {
container.appendChild(el);
}
});
<div class="house-senate widget widget-cpac-depth -horizontal">
<h1 class="widget__title">Committees</h1>
<a href="/en/?s=&category=BOIE">
<div class="committee">
<div class="color-green">BOIE</div>
<p>Board of Internal Economy</p>
</div>
</a>
<a href="/en/?s=&category=CACN">
<div class="committee">
<div class="color-green">CACN</div>
<p>Canada-China Relations</p>
</div>
</a>
<a href="/en/?s=&category=CHPC">
<div class="committee">
<div class="color-green">CHPC</div>
<p>Canadian Heritage</p>
</div>
</a>
<a href="/en/?s=&category=CIIT">
<div class="committee">
<div class="color-green">CIIT</div>
<p>International Trade</p>
</div>
</a>
</div>
If you need to add more sorting criteria (per your comment under the question), just add them in the sort callback; this question has answers showing how to sort an array of objects on multiple criteria.
I've assumed above that there aren't hundreds of these links. If there are, and if you see a performance problem with the above, you can remove the container from the DOM before moving the links around within it, then put it back:
Live Example:
function getLinkCategory(a) {
const matches = a.href.match(/category=([a-z]+)/i);
return matches ? matches[1] : '';
}
document.addEventListener("DOMContentLoaded", function () {
// Get the container
const container = document.querySelector(".house-senate");
// Remember its parent and following sibling and remove it
const parent = container.parentNode;
const sibling = container.nextSibling;
parent.removeChild(container);
// Get its immediate child `a` elements
const elems = [...container.children].filter(child => child.tagName === "A");
// Sort them
elems.sort((a, b) => getLinkCategory(a).localeCompare(getLinkCategory(b)));
// Add them back, which moves them
for (const el of elems) {
container.appendChild(el);
}
// Put the container back -- note this works even if the
// container was the last child in the parent
// and `sibling` is `null`.
parent.insertBefore(container, sibling);
});
<div>This is before the <code>div</code> with the links in it.</div>
<div class="house-senate widget widget-cpac-depth -horizontal">
<h1 class="widget__title">Committees</h1>
<a href="/en/?s=&category=BOIE">
<div class="committee">
<div class="color-green">BOIE</div>
<p>Board of Internal Economy</p>
</div>
</a>
<a href="/en/?s=&category=CACN">
<div class="committee">
<div class="color-green">CACN</div>
<p>Canada-China Relations</p>
</div>
</a>
<a href="/en/?s=&category=CHPC">
<div class="committee">
<div class="color-green">CHPC</div>
<p>Canadian Heritage</p>
</div>
</a>
<a href="/en/?s=&category=CIIT">
<div class="committee">
<div class="color-green">CIIT</div>
<p>International Trade</p>
</div>
</a>
</div>
<div>This is after the <code>div</code> with the links in it.</div>
Note: You're using modern language features, but the above relies on a modern browser feature (NodeList being iterable). If you're transpiling, it may not be that all the browsers you're targeting have the necessary feature, but for anything even vaguely modern, you can polyfill it; see my answer here for details.

Categories

Resources