How to find a parent with a known class in plain JavaScript - javascript

Please look at this html code first:
<div class="parent">
<div class="child">
</div>
<div class="child">
<!-- Some code here -->
</div>
</div>
<div class="parent>
<!-- some code here -->
</div>
Suppose, I'm in "child" class, & I need to get the closest parent class of a "child". Remember, there are more than one "parent" class, I just need the closest "parent" only using plain JavaScript, without using JQuery.
How to do that?

You can try using closest()
document.querySelectorAll('.child').forEach(function(child){
console.log(child.closest('.parent'));
});
<div class="parent">
<div class="child">
</div>
<div class="child">
<!-- Some code here -->
</div>
</div>
<div class="parent">
<!-- some code here -->
</div>

You can create a helper function and resuse it.Hope this is what you are looking for -
let getParentClass = node => {
return node.parentNode.classList.value;
}
let child = document.querySelectorAll('.child')[0]; // find the node
console.log(getParentClass(child));
<div class="parent">
<div class="child">
</div>
<div class="child">
<!-- Some code here -->
</div>
</div>
<div class="parent">
<!-- some code here -->
</div>

You can use parentNode to get the closest parent. Or you can use closest from vanilla js.
const child = document.querySelector('.child');
const closestParent = child.parentNode;
const child = document.querySelector('.child');
const closestParent = child.parentNode;
console.log(closestParent);
// Or you can use closest
const closest = child.closest('.parent');
console.log(closest);
<div class="parent">
<div class="child">
</div>
<div class="child">
<!-- Some code here -->
</div>
</div>

<!DOCTYPE html>
<div class="parent">
<div class="child">
</div>
<div class="child">
<!-- Some code here -->
</div>
</div>
<div class="parent">
<!-- some code here -->
</div>
<script>
const child = document.getElementsByClassName('child')[0];
console.log(child)
const parent = child.closest('.parent');
console.log(parent)
</script>

Use this.
var parent = document.querySelectorAll(".child");
for(var p = 0; p < parent.length; p++) {
parent[p].parentElement.classList.add("newClass");
//parent[p].//do something
}
or directly quote the parent
var parent = document.querySelectorAll(".child");
for(var p = 0; p < parent.length; p++) {
parent[p].closest(".parent").classList.add("newClass");
//parent[p].closest(".parent").//do something
}

Related

Wrapping elements while looping through HTMLCollection causes problem

I want to wrap each item of the container in a div. When I loop through HTMLCollection, some elements are accessed multiple times while others are left out
HTML
<div class="container">
<div class="item_1"></div>
<div class="item_2"></div>
<div class="item_3"></div>
<div class="item_4"></div>
<div class="item_5"></div>
<div class="item_6"></div>
<div class="item_7"></div>
<div class="item_8"></div>
<div class="item_9"></div>
</div>
JS
const container = document.querySelector('.container');
const items = container.children;
for(let i = 0; i < items.length; i++) {
const wrapper = document.createElement('div');
wrapper.classList.add('wrapper');
wrapper.appendChild(items[i]);
container.appendChild(wrapper);
}
Looping directly through HTMLCollection gives this bizarre result
<div class="container">
<div class="item_2"></div>
<div class="item_4"></div>
<div class="item_6"></div>
<div class="item_8"></div>
<div class="wrapper">
<div class="item_1"></div>
</div>
<div class="wrapper">
<div class="item_5"></div>
</div>
<div class="wrapper">
<div class="item_9"></div>
</div>
<div class="wrapper">
<div class="wrapper">
<div class="item_7"></div>
</div>
</div>
<div class="wrapper">
<div class="wrapper">
<div class="wrapper">
<div class="wrapper">
<div class="item_3"></div>
</div>
</div>
</div>
</div>
</div>
problem gets solved when I convert HTMLCollection to an Array
const items = Array.from(container.children);
I can't understand what causes such behavior
You were iterating the container.children list which you were also changing during the iterations. This messed up the iteration. You can solve this, as you mentioned yourself, by converting the container.children to an array because then you are not iterating over the live container.children list but over an array copy of that. This copy is still referring to the correct child elements so they are moved correctly with the appendChild() function.
As an alternative you can use the querySelecterAll() to retrieve all the elements you want to wrap.
const container = document.querySelector('.container');
const items = container.querySelectorAll('.container > *');
for(let i = 0; i < items.length; i++) {
const wrapper = document.createElement('div');
wrapper.classList.add('wrapper');
wrapper.appendChild(items[i]);
container.appendChild(wrapper);
}
.wrapper {
background-color: red;
}
<div class="container">
<div class="item_1">1</div>
<div class="item_2">2</div>
<div class="item_3">3</div>
<div class="item_4">4</div>
<div class="item_5">5</div>
<div class="item_6">6</div>
<div class="item_7">7</div>
<div class="item_8">8</div>
<div class="item_9">9</div>
</div>

Vanilla Javascript insertBefore() in for loop

I have the following html structure.
<div id="page1" class="page">
<div class="firstchild"></div>
<div class="secondchild"></div>
<div class="thirdchild"></div>
<div class="forthchild"></div>
</div>
<div id="page2" class="page">
<div class="firstchild"></div>
<div class="secondchild"></div>
<div class="thirdchild"></div>
<div class="forthchild"></div>
</div>
<div id="page3" class="page">
<div class="firstchild"></div>
<div class="secondchild"></div>
<div class="thirdchild"></div>
<div class="forthchild"></div>
</div>
And my javascript structure is.
var pageCLASS = frame.querySelectorAll(".page");
//var pageCLASS = frame.getElementsByClassName('page')[0];
var leng = pageCLASS.length;
for (var i = 0; i < leng; ++i) {
var pageID = frame.getElementById('page' + (i + 1));
var firstchild = frame.getElementsByClassName('firstchild')[0];
var secondchild = frame.getElementsByClassName('secondchild')[0];
var thirdchild = frame.getElementsByClassName('thirdchild')[0];
pageID.insertBefore(thirdchild, firstchild.nextSibling);
//pageCLASS.insertBefore(thirdchild, firstchild.nextSibling);
}
Now I have problems with the thirdchild being moved to below the firstchild and above the secondchild in all of page1, page2, and page3 together. The code above only moves it in page1, but for the other 2 which does nothing. The frame shown in the source is an iframe stored on the same domain with access to it's elements. Can I please get some advice on what I am doing wrong as I want to move all thirdchilds in each div to below the first child in each of their parent div?
The problem you are having is that you are constantly targeting the same elements with e.g.
var firstchild = frame.getElementsByClassName('firstchild')[0];
because this instruction always returns the first occurrence of such an element in the iframe and never the second or third.
In order to be sure that you are targeting the correct elements you can rewrite some of your code to only search for the elements that are contained within a certain parent and not inside the whole iframe.
You can then use something like this instead
var firstChild = pageID.querySelector('.firstchild');
which will only search for an element (the first occurrence) with class firstchild that is contained within some other element (in this case the element saved in pageID).
Check below (I exchanged the form for document so we can test here):
var pageCLASS = document.querySelectorAll(".page");
var leng = pageCLASS.length;
for (var i = 1; i <= leng; i++) {
var pageID = document.getElementById('page' + i);
var firstChild = pageID.querySelector('.firstchild');
var thirdChild = pageID.querySelector('.thirdchild');
firstChild.parentNode.insertBefore(thirdChild, firstChild.nextSibling);
}
.page {
border: 1px solid #09f;
}
<div id="page1" class="page">
<div class="firstchild">first child</div>
<div class="secondchild">second child</div>
<div class="thirdchild">third child</div>
<div class="forthchild">fourth child</div>
</div>
<div id="page2" class="page">
<div class="firstchild">first child</div>
<div class="secondchild">second child</div>
<div class="thirdchild">third child</div>
<div class="forthchild">fourth child</div>
</div>
<div id="page3" class="page">
<div class="firstchild">first child</div>
<div class="secondchild">second child</div>
<div class="thirdchild">third child</div>
<div class="forthchild">fourth child</div>
</div>

select content of div with DOM, but without child

there is HTML code:
<div id="parent">
<p>111111</p>
<div id="child">
<p>22222</p>
<div id="childer">
<p>33333</p>
</div>
</div>
</div>
i want only select "22222" in paragraph of div with id=child.
but when use document.getElementById("child").textContent it return "22222" and "33333".
i dont want use jQuery, can anyone help me?
thanks
You can use querySelector(), more info here.
The Document method querySelector() returns the first Element within the document that matches the specified selector, or group of selectors. If no matches are found, null is returned.
var value = document.querySelector('#child p').textContent;
console.log(value);
<div id="parent">
<p>111111</p>
<div id="child">
<p>22222</p>
<div id="childer">
<p>33333</p>
</div>
</div>
</div>
You can try using querySelector() which allows CSS like selector (#child p):
var elText = document.querySelector("#child p").textContent;
console.log(elText);
<div id="parent">
<p>111111</p>
<div id="child">
<p>22222</p>
<div id="childer">
<p>33333</p>
</div>
</div>
</div>
const setup = () => {
const child = document.querySelector('#child');
const p = child.querySelector('p');
console.log(p.textContent);
};
//load
window.addEventListener('load', setup);
<html>
<body>
<div id="parent">
<p>111111</p>
<div id="child">
<p>22222</p>
<div id="childer">
<p>33333</p>
</div>
</div>
</div>
</body>
</html>
document.getElementById("child").getElementsByTagName('p')[0].innerText;

Get Element that Parent not a class

I would like to return an element in javascript that does not have a class in its parent element.
For example, I would like to get the child class element in the following code snippet that does not have 'parent' as a class for the parent element:
<div>
<div class= "parent">
<div class="child">
Not to be selected
</div>
</div>
<div>
<div class="child">
To be selected
</div>
</div>
</div>
I tried to return it through xpath in protractor
You can use the :not selector .
console.log(document.querySelectorAll(':not(.parent) > .child'));
<div>
<div class= "parent">
<div class="child">
Not to be selected
</div>
</div>
<div>
<div class="child">
To be selected
</div>
</div>
</div>
There are a few ways to do this. Either you check if the class is there.
var elementList = [];
document.querySelectorAll("div.child").forEach(function(e) {
var parent = e.parentElement;
if(parent.classList == null || !parent.classList.contains("parent")) {
elementList.push(e);
}
})
console.log(elementList);
If the parent class is specific you can use the css :not attribute
var elementList = document.querySelectorAll("div:not(.parent) > div.child");
console.log(elementList);

How do I change the colour of an element within a div on rollover using Javascript?

I have a div that has a div within it.
<div class="parent">
<div class="child">
Content
</div>
</div>
<div class="parent">
<div class="child">
Content
</div>
</div>
<div class="parent">
<div class="child">
Content
</div>
</div>
...
I would like to change the colour of the ".child" element on hover using javascript. I have to use javascript and not jquery and not css.
Any ideas?
You need to add an eventListener to all of the children, listening forthe event mouseover.
var children = document.getElementsByClassName("child");
for(var i=0; i<children.length; i++) {
children[i].addEventListener("mouseover",function() {
this.style.background = "grey";
})
}
<div class="parent">
<div class="child">
Content
</div>
</div>
<div class="parent">
<div class="child">
Content
</div>
</div>
<div class="parent">
<div class="child">
Content
</div>
</div>
If you want the children to go back to white when the mouse leaves use the mouseout event with a new eventListener.
children[i].addEventListener("mouseout",function() {
this.style.background = "white";
})

Categories

Resources