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
5
Answers
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 referenceEdit:
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
Simply select all Headlines and use a
forEach
loop to loop through all those headlines. Then select the next sibling and count all elements that has the classchild_element
within:If the header (
h2.amount_title
) is always directly beforediv.parent_container
you can usepreviousElementSibling
to give[data-children]
its value. The snippet uses css to display the amount of child elements.When there may be elements between
h2.amount_title
anddiv.parent_container
its better to wrap the elements within a div.You can use the is and has selectors with the adjacent sibling combinator
+
to get just the .amount_title elements that have .parent_container as an adjacent sibling.It then loops over them to update their data-children attribute and textContent. It doesn’t visit any .amount_title element that doesn’t have a .parent_container as an adjacent sibling, so
.nextElementSibling
should always return a .parent_container element.The OP should make use of
MutationObserver
andMutationRecord
where the latter gets provided as an array of records to an observer’s callback/handler function.As for the OP’s use case, one just needs to have a look at/into both
NodeList
‘s of each record which areaddedNodes
andremovedNodes
. A child-count change has happened whenever either of the node-list’s carries at least a single element-reference.The decision for
MutationObserver
enables a maximum generic implementation for it decouples the change-handling/management entirely from any code which would trigger DOM-mutations such as element-insertion and -deletion.In order to not being forced to having to observe the entire DOM-tree one would make use of a component-like approach based on just some more of the already introduced
data-*
global attributes (in cooperation with an element’s relateddataset
-property).Already the minimum set of related
data-*
attributes like …… and …
… enables a fully generic implementation of displaying/updating child-count changes; it even is fully agnostic to DOM structures. It does work regardless of chosen tag-names, class-names and nesting of markup structures.
For instance
[data-child-count-for="23fd215b-4c2a-4861-b53a-5c517e67a56e"]
marks an element which has to display/update a child-count change. The element’s relateddataset.childCountFor
-value does identify the element where the child-count change is expected to happen. It is the very element which was marked by e.g.[data-child-count-id="23fd215b-4c2a-4861-b53a-5c517e67a56e"]
.The next provided example code demonstrates how one would identify such a loosely coupled (markup and DOM -wise) component, and how one would create a mutation observer for each such component.