'Rearrange divs - Place each div under each image (javascript - jQuery)
I have the following structure example:
<div class="main">
<div class="image">Image1</div>
<div class="image">Image2</div>
<div class="image">Image3</div>
</div>
<div class="side">
<div class="Banner">Banner1</div>
<div class="Banner">Banner2</div>
<div class="Banner">Banner3</div>
<div class="Banner">Banner4</div>
</div>
I want to make a script that will take each banner and placed under each image.
<div class="main">
<div class="image">Image1</div>
<div class="Banner">Banner1</div>
<div class="image">Image2</div>
<div class="Banner">Banner2</div>
<div class="image">Image3</div>
<div class="Banner">Banner3</div>
<div class="Banner">Banner4</div>
</div>
<div class="side"></div>
Basically there are some images placed one after another and then some banners placed one after another.
Image1 Image2 Image3 Banner1 Banner2 Banner3 Banner4
I need to take each banner and place it under each image so I can have:
Image1 Banner1 Image2 Banner2 Image3 Banner3 Banner4
I cannot change the html to manually placed the banners, I need to use a more advanced script JS and or jquery ..
.content {display:flex; max-width:800px;min-width:300px;gap:20px;margin:auto;}
.main { flex: 70%;}.main2 {max-width:400px;}
.side { flex: 30%; padding:10px;}.img { background:blue;}.banner { background:red;}
.img, .banner { width:100%; min-width:50px; height:50px;display:grid;place-items:center; color: #fff; margin:10px auto;}
<h2>Rearrange content - Place each div (banner) under each image </h2>
<div class="content">
<div class="main">
<div class="img">Image 1</div>
<div class="img">Image 2</div>
<div class="img">Image 3</div>
<div class="img">Image 4</div>
<div class="img">Image 5</div>
<div class="img">Image 6</div>
<p> Multiple DIVs with images ...
<br> ...
</div>
<div class="side">
<div class="banner">Banner1</div>
<div class="banner">Banner2</div>
<div class="banner">Banner3</div>
<div class="banner">Banner4</div>
<div class="banner">Banner5</div>
<div class="banner">Banner6</div>
<div class="banner">Banner7</div>
<div class="banner">Banner8</div>
<div class="banner">Banner9</div>
<div class="banner">Banner10</div>
</div>
</div>
<hr>
<h2> This is how it should look </h2>
<div class="main2">
<div class="img">Image 1</div>
<div class="banner">Banner1</div>
<div class="img">Image 2</div>
<div class="banner">Banner2</div>
<div class="img">Image 3</div>
<div class="banner">Banner3</div>
<div class="img">Image 4</div>
<div class="banner">Banner4</div>
<div class="img">Image 5</div>
<div class="banner">Banner5</div>
<div class="img">Image 6</div>
<div class="banner">Banner6</div>
<div class="banner">Banner7</div>
<div class="banner">Banner8</div>
<div class="banner">Banner9</div>
<div class="banner">Banner10</div>
</div>
Solution 1:[1]
To do what you require you can loop through the .banner elements and use their index to place them underneath the related .img element by their indexes using insertAfter(). Something like this:
let $imgs = $('.content .main .img');
$('.content .side .banner').each((i, el) => $(el).insertAfter($imgs[i]));
.content {
display: flex;
max-width: 800px;
min-width: 300px;
gap: 20px;
margin: auto;
}
.main {
flex: 70%;
}
.img,
.banner {
width: 100%;
min-width: 50px;
height: 50px;
display: grid;
place-items: center;
color: #fff;
margin: 10px auto;
}
.img {
background: blue;
}
.banner {
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="content">
<div class="main">
<div class="img">Image 1</div>
<div class="img">Image 2</div>
<div class="img">Image 3</div>
<div class="img">Image 4</div>
<div class="img">Image 5</div>
<div class="img">Image 6</div>
</div>
<div class="side">
<div class="banner">Banner1</div>
<div class="banner">Banner2</div>
<div class="banner">Banner3</div>
<div class="banner">Banner4</div>
<div class="banner">Banner5</div>
<div class="banner">Banner6</div>
</div>
</div>
Solution 2:[2]
Well, to answer my own question, it was hard for me since I don't know JS that well.
I managed to make something that also randomizes the banners and I've used jquery.
jQuery("#btn").click(function() {
var cards = jQuery(".side .banner");
for(var i = 0; i < cards.length; i++){
var target = Math.floor(Math.random() * cards.length -1) + 1;
var target2 = Math.floor(Math.random() * cards.length -1) +1;
cards.eq(target).before(cards.eq(target2));
}
cards = jQuery(".side .banner");
var images = jQuery(".content.desk .img");
if (cards.length < images.length) {
for (var i=0; i<cards.length; i++) {
images.eq(i).after(cards.eq(i));
}
} else {
for (var i=0; i<images.length; i++) {
images.eq(i).after(cards.eq(i))
}
for (var i=images.length; i<cards.length; i++){
cards.eq(i-1).after(cards.eq(i));
}
}
});
body {
max-width:1250px;
margin:auto;
}
h1, h2, h3, h4 {
text-align:center;
}
.content {
display:flex;
max-width:800px;
min-width:300px;
gap:20px;
margin:auto;
}
.main {
flex: 70%;
}
.side {
flex: 30%;
background: lightblue;
padding:10px;
}
.img {
background:blue;
}
.banner {
background:red;
}
.img, .banner {
width:100%;
min-width:50px;
height:50px;
display:grid;
place-items: center;
color: #fff;
margin:10px auto;
}
<body>
<h1>Rearrange content</h1>
<div class="content desk">
<div class="main">
<button id="btn">Click to reorder and randomize</button>
<div class="img">Image 1</div>
<div class="img">Image 2</div>
<div class="img">Image 3</div>
<div class="img">Image 4</div>
<div class="img">Image 5</div>
<div class="img">Image 6</div>
<div class="img">Image 7</div>
<div class="img">Image 8</div>
<div class="img">Image 9</div>
<div class="img">Image 10</div>
<div class="img">Image 11</div>
<div class="img">Image 12</div>
<div class="img">Image 13</div>
</div>
<div class="side">
<div class="banner">Banner1</div>
<div class="banner">Banner2</div>
<div class="banner">Banner3</div>
<div class="banner">Banner4</div>
<div class="banner">Banner5</div>
<div class="banner">Banner6</div>
<div class="banner">Banner7</div>
<div class="banner">Banner8</div>
<div class="banner">Banner9</div>
<div class="banner">Banner10</div>
</div>
</div>
<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
</body>
Solution 3:[3]
Edit:
Here's another method that's a bit more concise.
const main = document.querySelectorAll('.main .img');
const side = document.querySelectorAll('.side .banner');
let offset;
side.forEach((banner, idx) => {
const img = main[idx] || offset;
img.insertAdjacentElement('afterend', banner);
offset = banner;
});
.content { display: flex }
.main, .side { flex-grow: 1 }
.content,
.main2 {
font-family: sans-serif;
line-height: 2;
color: white;
}
.img { background-color: red; margin: 3px;}
.banner { background-color: blue; margin: 3px;}
<div class="body">
<h2>Rearrange content - Place each div (banner) under each image </h2>
<div class="content">
<div class="main">
<div class="img">Image 1</div>
<div class="img">Image 2</div>
<div class="img">Image 3</div>
<div class="img">Image 4</div>
<div class="img">Image 5</div>
<div class="img">Image 6</div>
</div>
<div class="side">
<div class="banner">Banner1</div>
<div class="banner">Banner2</div>
<div class="banner">Banner3</div>
<div class="banner">Banner4</div>
<div class="banner">Banner5</div>
<div class="banner">Banner6</div>
<div class="banner">Banner7</div>
<div class="banner">Banner8</div>
<div class="banner">Banner9</div>
<div class="banner">Banner10</div>
</div>
</div>
</div>
Original:
You need to loop over the elements and then merge/combine the arrays as you are looping. There are multiple ways this can be done. Here's one way (with comments) that uses reduce to combine the elements.
If you're starting out with JS, I would suggest using a simple for loop to start off.
When you run the code snippet below, the original will be in Red. Clicking the button will merge the elements, append them, and display them in Green.
Good luck!
// I've wrapped this in a function so I can call it.
function rearrange() {
// First I'm going to query all the divs with 'img' class
// From that, I'll call 'Array.from' to create an array.
const images = Array.from(document.querySelectorAll('.img'));
// Similar to above, but for all the 'banner' divs.
const banners = Array.from(document.querySelectorAll('.banner'));
// This is my loop. I'm using .reduce, but for/while/.forEach/etc
// would all have worked.
// I'm going to loop over the images and push image/banner into
// a new container
const container = images.reduce(function (el, image) {
// get the first "banner" div
const banner = banners.shift();
// append the image div, first
el.appendChild(image);
// if a banner exists, append that
if (banner) {
el.appendChild(banner);
}
// as this is a reducer, i return my accumulator of divs
return el;
}, document.createElement('div'));
// As image/banner could differ in length, push any additional
// banner divs to the container
if (banners.length > 0) {
banners.forEach(banner => container.appendChild(banner));
}
// Add the new class name
container.classList.add('main2');
// Finally, append to body
document.querySelector('.body').appendChild(container);
}
// My event handler to run
document.querySelector('#rearrange').addEventListener('click', rearrange);
.content { display: flex }
.main, .side { flex-grow: 1 }
.content,
.main2 {
font-family: sans-serif;
line-height: 2;
color: white;
}
.img { background-color: red; margin: 3px;}
.banner { background-color: blue; margin: 3px;}
<div class="body">
<button id="rearrange">Click here to re-arrange</button>
<h2>Rearrange content - Place each div (banner) under each image </h2>
<div class="content">
<div class="main">
<div class="img">Image 1</div>
<div class="img">Image 2</div>
<div class="img">Image 3</div>
<div class="img">Image 4</div>
<div class="img">Image 5</div>
<div class="img">Image 6</div>
</div>
<div class="side">
<div class="banner">Banner1</div>
<div class="banner">Banner2</div>
<div class="banner">Banner3</div>
<div class="banner">Banner4</div>
<div class="banner">Banner5</div>
<div class="banner">Banner6</div>
<div class="banner">Banner7</div>
<div class="banner">Banner8</div>
<div class="banner">Banner9</div>
<div class="banner">Banner10</div>
</div>
</div>
<h2>Rearranged:</h2>
<hr />
</div>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Rory McCrossan |
| Solution 2 | |
| Solution 3 |
