So I have the following structure with multiple <div>
elements where I want to display the children inside each of it in a data attribute (data-children
). Instead of manually changing the attribute, I'd like it to be dynamic with JS so it changes when I add/delete children elements.
<h2 class="amount_title" data-children="1">
The amount of children of this element is
</h2>
<div class="parent_container">
<div class="children_element">
<div>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<button>Button</button>
</div>
</div>
<h2 class="amount_title" data-children="2">
The amount of children of this element is
</h2>
<div class="parent_container">
<div class="children_element">
<div>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<button>Button</button>
</div>
<div class="children_element">
<div>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<button>Button</button>
</div>
</div>
So right now I'm doing the following to get each element's children and populate the data-attribute
of each title:
const parentContainer = document.querySelectorAll('.parent_container')
const amountTitle = document.querySelectorAll('.amount_title')
let childrenAmount1 = parentContainer[0].childElementCount
amountTitle[0].dataset.children = childrenAmount1
let childrenAmount2 = parentContainer[1].childElementCount
amountTitle[1].dataset.children = childrenAmount2
I have a few of these so it's obviously not ideal. Which function could help me to go through all of them and populate each dataset accordingly with the amount of children for each element? Thank you.
I tried to do a for () loop but all the datasets grabbed the amount of children from the last item in the array
Based on this configuration, your best strategy is to get the next element after each title. Although I would recommend a wrapper to set the title based on each wrapper contents .wrapper > amount_title|parent_container
to loop through all wrappers first and get its children from the wrapper reference
const titles = document.querySelectorAll(".amount_title");
titles.forEach((title) => {
const next = title.nextElementSibling;
if (!next.classList.contains("parent_container")) { return false; } // killswitch
title.innerHTML = `The amount of children of this element is ${ next.childElementCount }`;
});
<h2 class="amount_title" data-children="1">The amount of children of this element is </h2>
<div class="parent_container">
<div class="children_element">
<div>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<button>Button</button>
</div>
</div>
<h2 class="amount_title" data-children="2">The amount of children of this element is </h2>
<div class="parent_container">
<div class="children_element">
<div>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<button>Button</button>
</div>
<div class="children_element">
<div>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<button>Button</button>
</div>
</div>
Edit: The wrapper method:
This method allows to move any element inside without caring about the order of the elements. When the other method works, this one allows you to set the title before or after the contents without breaking
const wrappers = document.querySelectorAll(".wrapper");
wrappers.forEach((wrapper) => {
const title = wrapper.querySelector(".amount_title");
const contents = wrapper.querySelector(".parent_container");
if (!title || !contents) { return; } // killswitch
title.innerText = `The amount of children of this element is ${ contents.childElementCount }`
});
<div class="wrapper">
<h2 class="amount_title" data-children="1">The amount of children of this element is </h2>
<div class="parent_container">
<div class="children_element">
<div>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<button>Button</button>
</div>
</div>
</div>
<div class="wrapper">
<h2 class="amount_title" data-children="2">The amount of children of this element is </h2>
<div class="parent_container">
<div class="children_element">
<div>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<button>Button</button>
</div>
<div class="children_element">
<div>
<p>Lorem ipsum dolor sit amet.</p>
</div>
<button>Button</button>
</div>
</div>
</div>