How to get outermost parent node of inner child in plain JavaScript? - javascript

I got stuck in a problem, I wish to write a script that can show all the div ids of an inner div, for example:
<body id="bd">
<div id="canvas">
<div id="nd1">
<div>
My text
</div>
</div>
<div id="nd2">
<div id="hd">Some Text</div>
<div>
<div>
What I want is suppose when I click on div with no ID defined inside "nd1", I should get its parent div (i.e. nd1), and the outermost parent, kind of thing I want.

try
var allChildNodes = document.querySelectorAll("#nd1 div");
nodes = Array.prototype.slice.call(allChildNodes ,0);
nodes.forEach(function(node){
node.addEventListener("click", function(){
console.log("Outer parent" + node.parentNode.outerHTML);
console.log("Outermost parent" + node.parentNode.parentNode.outerHTML);
});
});
To get the array of parent divs
var allChildNodes = document.querySelectorAll("#nd1 div");
nodes = Array.prototype.slice.call(allChildNodes ,0);
nodes.forEach(function(node){
node.addEventListener("click", function(){
var parentDivs = [];
while( !node.parentNode )
{
parentDivs.push(node.parentNode);
node = node.parentNode;
}
console.log("parents" + parentDivs);
});
});
For matching multiple divs starting from a specific string
var allChildNodes = document.querySelectorAll("[id^='nd'] div");

Related

How to get index number of clicked element from MouseEvent object

I am trying to get the index of the clicked element from the MouseEvent object. When I go console click event objects "path" property and hover to first array item it marks actually clicked element.
I wonder how come engine knows which was clicked? Because event.path[0] selector doesn't contain index number of clicked element.
<div id="container">
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
</div>
jsfiddle: https://jsfiddle.net/9n3f7mcr/
You can use Array#indexOf on the children of the parent of event.target, if all the elements you may want the index of have the same parent.
document.addEventListener('click', function (e) {
var target = e.target;
var parent = target.parentNode;
var index = [].indexOf.call(parent.children, target);
console.log("index:", index);
});
<div id="container">
<div>1z</div>
<div>2z</div>
<div>3z</div>
<div>4z</div>
<div>5z</div>
<div>6z</div>
</div>
There are a few ways to go about this depending on how you want to use the index of each child element. I think using data attributes is generally a good approach:
HTML
<div id="container">
<div data-id="1">1z</div>
<div data-id="2">2z</div>
<div data-id="3">3z</div>
<div data-id="4">4z</div>
<div data-id="5">5z</div>
<div data-id="6">6z</div>
</div>
JS
const container = document.getElementById("container");
function handleClick(evt) {
const childNode = evt.target.closest("div");
console.log(childNode.dataset.id);
}
container.addEventListener("click", handleClick, false);

Javascript how to append node in its correct index with wrapper

I need to get user entered markup (tables) and if the table does not contain a div with a the class="table", I need to add the div & class. I need to ignore any other children, such as p, span, and only target elements with tables.
<div class="parent">
<div class="table"><table></table></div>
<div class="table"><table></table></div>
<table></table>
<div><table></table></div>
<div class="table"><table></table></div>
<p></p>
<span></span>
</div>
You can see in the nodelist above, node index 2,3 both need a wrapper div with the class="table", but ignore the p and span.
[].map.call(table, (node) => {
if (!node.parentNode.classList.contains('table')) {
const parent = document.getElementsByClassName('parent');
[].map.call(parent, (nodeChild) => {
const addWrap = document.createElement('div');
addWrap.classList.add('table');
addWrap.appendChild(node);
nodeChild.append(addWrap);
});
}
});
I have tried this, but it appends the node with a wrapper div at the bottom of the index. How do I get the nodes to append in their correct order with the wrapper div? Thanks.
You're better off using a for/loop (using map here is an anti-pattern) to iterate over the child nodes of the parent node and replace the current child node with the new created element.
childNodes
replaceChild
Inspect the output in dev tools to see the change.
const parent = document.querySelector('.parent');
const { childNodes } = parent;
for (let i = 0; i < childNodes.length; i++) {
const el = childNodes[i];
// If the node type is an element
if (el.nodeType === 1) {
// If element is a div add a class
// if it's missing
if (el.tagName === 'DIV' && !el.classList.contains('table')) {
el.classList.add('table');
}
if (el.tagName === 'TABLE') {
const div = document.createElement('div');
div.classList.add('table');
div.appendChild(el);
// Replace the child node with the new div node
parent.replaceChild(div, childNodes[i]);
}
}
};
<div class="parent">
<div class="table"><table></table></div>
<div class="table"><table></table></div>
<table></table>
<div><table></table></div>
<div class="table"><table></table></div>
<p></p>
<span></span>
</div>
I think I understood what you're trying to do. This should find child nodes without a "table" class and wrap them in a div with a "table" class. When you run the snippet it won't show any thing as your elements don't have any content but you should be able to inspect them to see the changes.
// get all parent divs
var parents = document.getElementsByClassName("parent");
// loop over parent divs
for (var i = 0; i < parents.length; i++) {
// get a single parent div
var parent = parents[i];
// loop over child nodes
for (var j = 0; j < parent.childNodes.length; j++) {
// get a single child node
var childNode = parent.childNodes[j];
// if this child node is type 1 (element node)
// and does not have a class of table
if (
childNode.nodeType === 1 &&
!childNode.classList.contains("table")
) {
// create a new div element
var wrap = document.createElement('div');
// give it a class of table
wrap.classList.add("table");
// append a clone of the child node
wrap.appendChild(childNode.cloneNode());
// replace the old child node with the wrapped child node
parent.replaceChild(wrap, childNode);
}
}
}
<div class="parent">
<div class="table"></div>
<div class="table"></div>
<table></table>
<div></div>
<div class="table"></div>
</div>

Target an Element within another Element

I'm looking to try to find an element inside another element then add an ID to it as this is a multi dynamic paged Prince document, so far I have the code below but unsure of how to check if the title__container-page DIV is inside the page-first DIV, as there'as more than one page-first element, I only want to add the ID to any page-first element that contains the title__container-page element, at the moment it's adding that ID to all of them.
<script>
var checkedValue = "title__container-page";
var targetModule = document.getElementsByClassName('page-first');
var checkedArray = checkedValue.split(" ");
console.log(checkedArray);
checkedArray.forEach(function (val, key) {
if (val === "") {
checkedArray.splice(key, 1)
}
if (checkedArray.length > 0) {
targetModule[key].id = "column-padding-top";
}
})
</script>
If you want to target an element inside another element you can use queryselector.
var span = document.querySelector("#whatever .something");
span.id = "newId";
console.log(document.getElementById('newId'));
<div id=whatever>
<span class=something></span>
</div>
If you want to do it the long way you can change the context of getElementsByClassName.
var div = document.getElementById("whatever");
var span = div.getElementsByClassName("something")[0];
span.id = "newId";
console.log(document.getElementById('newId'));
<div id=whatever>
<span class=something></span>
</div>
Here are 5 parent divs with class='page-first', 3 of them containing child divs with class='title__container-page':
<div class='page-first'>
<div class='title__container-page'></div>
</div>
<div class='page-first'>
<div class='title__container-page'></div>
</div>
<div class='page-first'>
</div>
<div class='page-first'>
</div>
<div class='page-first'>
<div class='title__container-page'></div>
</div>
Inspect Element:
The following scans over all parent divs, and adds an ID to the parent found to have a child with class='title__container-page':
$('.page-first').each(function() {
this_childs = $(this).children();
this_childs.each(function() {
if($(this).attr('class') == 'title__container-page') {
add_id = 'div_' + Math.floor((Math.random() * 100000) + 1);
$(this).parent().attr('id', add_id); // add id to page-first element
}
})
})
Inspect Element:
This is assuming you can use jQuery.

swap 2 div's index using pure javascript

I have a parent div and it has 9 same div's am trying to swap two div's index. Following is my code:
HTML:
<div id="cont" class="container">
<div class="no">1</div>
<div class="no">2</div>
<div class="no">3</div>
<div class="blank"></div>
<div class="no">4</div>
<div class="no">5</div>
<div class="no">6</div>
<div class="no">7</div>
<div class="no">8</div>
</div>
now I want to swap say 5th and 6th indexed elements. I have no clue how to do that in JavaScript. I know there is function called .index() but how to do that in pure JS.
Here's one implementation: http://jsfiddle.net/x8hWj/2/
function swap(idx1, idx2) {
var container = document.getElementById('cont');
// ditch text nodes and the like
var children = Array.prototype.filter.call(
container.childNodes,
function(node) {
return node.nodeType === 1;
}
);
// get references to the relevant children
var el1 = children[idx1];
var el2 = children[idx2];
var el2next = children[idx2 + 1];
// put the second element before the first
container.insertBefore(el2, el1);
// now put the first element where the second used to be
if (el2next) container.insertBefore(el1, el2next);
else container.appendChild(el1);
}
This starts by getting a list of all element child nodes, then uses insertBefore to rearrange them.

Javascript - Get child's text value

How can I get the text value from an elements's child?
Say I have this code on a page:
<div class='geshitop'>
[ CODE ] [ PLAIN-TEXT ]
</div>
<div class='geshimain'>
<pre><div class="text" style="font-family:monospace;">Code goes here...</div></pre>
</div>
The function copy():
<script type="text/javascript">
function copy() {
var text = this.parent.getElementsByName("text");
var code = text[0].value;
var popup = window.open("", "window", "resizeable,width=400,height=300");
popup.document.write("<textarea name='code' cols='40' rows='15'></textarea>");
popup.code.value = code;
}
How would I go about getting that child's data: the <div class "text">. How can I get that from the parent?
I'm still having problems. If there is two codeboxes on one page, then it does not work. Remember, I am unable to use ID's. It must be classes.
If I was able to use jQuery this would be easy.
Get a reference to the node you want to retrieve text from and try:
someNode.firstChild.nodeValue
When you have a node like this:
<span>Here is some text</span>
You're actually looking at two nodes, a span node which has a text node child. In DOM, that text node child's nodeValue is "Here is some text"
put an ID on the tag you want to get its data from.
this way will only grab the first child of the div node:
function copy(){
var text = document.getElementById( "YOU_TAG_NAME" ).firstChild;
//do stuff
}
this will grab all of the data in the node, but don't do this unless you have control over what goes into that div tag:
function copy(){
var text = document.getElementById( "YOU_TAG_NAME" ).innerHtml;
//do stuff
}
To clarify: Are you trying to get the css from the "text" class to display?
Just a thought, you could try using id attributes to get what you need.
Try this:
Change your HTML slightly. The "javascript:" prefix isn't necessary inside an onclick handler. Also, pass a reference of "this" to your copy function:
<div class='geshitop'>
[ CODE ] [ PLAIN-TEXT ]
</div>
<div class='geshimain'>
<pre><div class="text" style="font-family:monospace;">Code goes here...</div></pre>
</div>
Having done that, alter your copy function to accept the new parameter. Then you just have to locate the correct node. From the question, I think you are looking for the next <div class="text"> that is a child of the <div class="geshimain"> that is the next sibling of the parent node that contains the link that was clicked. This function should accomplish that:
function copy(node) {
node = node.parentNode; // <div class="geshitop">
// Loop over adjacent siblings, looking for the next geshimain.
while (node.nextSibling) {
node = node.nextSibling;
if (node.nodeName === 'DIV' && node.className === 'geshimain') {
break;
}
}
if (!node) {
throw new Error("Could not locate geshimain");
}
// Locate the <div class="text">
node = (function () {
var divs = node.getElementsByTagName('div');
for (var x = 0; x < divs.length; x++) {
if (divs[x].className === 'text') {
return divs[x];
}
}
return null;
}());
if (!node) {
throw new Error("Could not locate text");
}
node =
'<textarea name="code" cols="40" rows="15">' + node.innerHTML + "</textarea>";
popup = window.open("", "window", "resizeable,width=400,height=300");
popup.document.write(node);
popup.document.close();
}
Good luck!

Categories