I'm need to count specific divs and after each X divs insert another div with a paragraph in it. All in pure JavaScript.
I am done with counting the specific divs but I don't know how to handle the loop and insert the container and the paragraph.
<div class="main">
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
</div>
<script>
count = document.getElementsByClassName("special-div").length; // Output: X
</script>
A basic for statement would be suitable for this problem.
Use querySelectorAll instead of getElementsByClassName as it's easier to manage - QSA returns an array-like static node list whereas gEBCN returns a live HTML collection which may trip you up when you start inserting new elements during its iteration.
To find out where you should add the new div element use the remainder operator (also called "modulo"). As you iterate over the node list check to see if dividing the current index + 1 (arrays are zero-based) by the specified number results in zero. If it does, add in the new div element after the current one.
Note: I've separated out the code to create a new div element into a function to keep things simple.
const divs = document.querySelectorAll('.special-div');
// Loop over the array-like structure that
// qsa returns. Find the remainder of dividing
// the index by the supplied `n` argument. If it's
// zero create a new div element and add it `after`
// the current div
function insertAfter(n, text) {
for (let i = 0; i < divs.length; i++) {
if ((i + 1) % n === 0) {
const div = createDiv(text);
divs[i].after(div);
}
}
}
// For convenience a function that creates
// a new paragragh element wrapped in a div.
// It uses the text passed in as an argument
function createDiv(text) {
const div = document.createElement('div');
div.className = 'special-div';
const para = document.createElement('p');
para.textContent = 'new!';
div.appendChild(para);
return div;
}
// Call the main function. The arguments are
// the count where you add a new div, and the
// text you want to appear in the paragraph
insertAfter(2, 'new!');
div.special-div p { color: red; }
<div class="main">
<div class="special-div">one</div>
<div class="special-div">two</div>
<div class="special-div">three</div>
<div class="special-div">four</div>
<div class="special-div">five</div>
<div class="special-div">six</div>
</div>
This iterates the nodes with the special-div class, keeping track of the index. For non-zero indexes divisible by interval it creates and inserts a new div.
const interval = 3;
const parent = document.getElementById("parent");
const elements = [...document.getElementsByClassName("special-div")];
const divWithText = text => {
const newNode = document.createElement("div");
newNode.appendChild(document.createTextNode(text));
return newNode
};
elements.forEach((node,i) => {
if (i && i % interval === 0) {
parent.insertBefore(divWithText("new div"), node);
}
});
<div id="parent" class="main">
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
</div>
Sorry, I'm not quite sure what output you are expecting is like.
How about using .insertAdjacentHTML(<position>, <text>)? It inserts HTML code to a specified element. You don't need to count divs :)
element.insertAdjacentHTML()
element like main in my code.position: 'beforeend'
</div> of .mainposition: 'afterend'
</div> of .special-divconst main = document.querySelector('.main');
let html = `
<div>
<p>new</p>
</div>
`
// Insert html at the end of all children of .main
main.insertAdjacentHTML('beforeend', html);
<div class="main">
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
<div class="special-div">div 1</div>
</div>
const targetDivs = document.querySelectorAll('.special-div');
let html = `
<div>
<p>new</p>
</div>
`
// Insert html after every specific div
targetDivs.forEach(div => div.insertAdjacentHTML('afterend', html));
// you can't do this: targetDivs.insertAdjacent()
// Because targetDivs is a NodeList which is like an array [].
// You have to use .insertAdjacent() on every div one by one,
// not on an array(NodeList)
<div class="main">
<div class="special-div">div 1</div>
<hr>
<div>Ignore this div</div>
<hr>
<div class="special-div">div 1</div>
<hr>
<div class="special-div">div 1</div>
</div>