1 year ago
#348258
Dr.Random
Replace two ( relative positioned ) HTML elements with JQUERY animation depending on object index and button click
My goal is the following.
I have a codepen example but i will write it here too.
I have an object coming from a backend which looks like this:
var boxes = {
box1: { index: 1, name: "box1" },
box2: { index: 2, name: "box2" },
box3: { index: 3, name: "box3" },
box4: { index: 4, name: "box4" },
box5: { index: 5, name: "box5" }
};
I have to append them as HTML elements into a div.
Which i have done like this:
function appendBoxes() {
for (const boxID in boxes) {
if (Object.hasOwnProperty.call(boxes, boxID)) {
const box = boxes[boxID];
$(".wrapper").append(`
<div class="box" id="${boxID}">
<button class="manage" action="left">
left
</button>
<button class="manage" action="right">
right
</button>
<h2>${box.name}</h2>
</div>`);
}
}
}
There are two buttons on each element, which should replace the position with either the one before the element or one after the element, depending on the index inside the object. My approach is jquery animation, because the project already using jquery. Here is the whole JS:
var boxes = {
box1: { index: 1, name: "box1" },
box2: { index: 2, name: "box2" },
box3: { index: 3, name: "box3" },
box4: { index: 4, name: "box4" },
box5: { index: 5, name: "box5" }
};
function appendBoxes() {
for (const boxID in boxes) {
if (Object.hasOwnProperty.call(boxes, boxID)) {
const box = boxes[boxID];
$(".wrapper").append(`
<div class="box" id="${boxID}">
<button class="manage" action="-1">
left
</button>
<button class="manage" action="1">
right
</button>
<h2>${box.name}</h2>
</div>`);
}
}
}
function getBoxID_WithIndex(index) {
for (const boxID in boxes) {
if (Object.hasOwnProperty.call(boxes, boxID)) {
const box = boxes[boxID];
if (box.index == index) {
return boxID;
}
}
}
return false;
}
$(document).ready(function () {
appendBoxes();
let animDurationMS = 300;
let boxesLength = Object.keys(boxes).length;
$(".manage").on("click", function () {
let indexToAdd = parseInt( $(this).attr("action") );
let currentBoxID = $(this).closest(".box").attr("id");
let currentBoxIndex = boxes[currentBoxID].index;
let nextBoxIndex = currentBoxIndex + indexToAdd;
if( nextBoxIndex < 1 || nextBoxIndex > boxesLength ){
console.log("Out of bounds");
return false;
}
let nextBoxID = getBoxID_WithIndex(nextBoxIndex);
// Replace the indexes inside the object
boxes[currentBoxID].index = nextBoxIndex;
boxes[nextBoxID].index = currentBoxIndex;
let currBoxPOs = $(`#${currentBoxID}`).position();
let nextBoxPOs = $(`#${nextBoxID}`).position();
// Animate each box to the other box's position
$(`#${nextBoxID}`).addClass("moving").animate({
top: currBoxPOs.top+"px",
left: currBoxPOs.left+"px"
},{
duration:animDurationMS
});
$(`#${currentBoxID}`).addClass("moving").animate({
top:nextBoxPOs.top+"px",
left:nextBoxPOs.left+"px"
},{
duration:animDurationMS
});
});
});
The problem is when i click a button, just one element is animating, but not the other. I tried with dequeue the animations, and give the same queue to both animation, but nothing helps. The goal is to replace any two boxes in the set and adjust it's index inside the object accordingly.
Here is a snippet:
// Boxes object can be any length with index always start from one
var boxes = {
box1: { index: 1, name: "box1" },
box2: { index: 2, name: "box2" },
box3: { index: 3, name: "box3" },
box4: { index: 4, name: "box4" },
box5: { index: 5, name: "box5" }
};
function appendBoxes() {
for (const boxID in boxes) {
if (Object.hasOwnProperty.call(boxes, boxID)) {
const box = boxes[boxID];
$(".wrapper").append(`
<div class="box" id="${boxID}">
<button class="manage" action="-1">
left
</button>
<button class="manage" action="1">
right
</button>
<h2>${box.name}</h2>
</div>`);
}
}
}
function getBoxID_WithIndex(index) {
for (const boxID in boxes) {
if (Object.hasOwnProperty.call(boxes, boxID)) {
const box = boxes[boxID];
if (box.index == index) {
return boxID;
}
}
}
return false;
}
$(document).ready(function () {
appendBoxes();
let animDurationMS = 300;
let boxesLength = Object.keys(boxes).length;
$(".manage").on("click", function () {
let indexToAdd = parseInt( $(this).attr("action") );
let currentBoxID = $(this).closest(".box").attr("id");
let currentBoxIndex = boxes[currentBoxID].index;
let nextBoxIndex = currentBoxIndex + indexToAdd;
if( nextBoxIndex < 1 || nextBoxIndex > boxesLength ){
console.log("Out of bounds");
return false;
}
let nextBoxID = getBoxID_WithIndex(nextBoxIndex);
// Replace the indexes inside the object
boxes[currentBoxID].index = nextBoxIndex;
boxes[nextBoxID].index = currentBoxIndex;
let currBoxPOs = $(`#${currentBoxID}`).position();
let nextBoxPOs = $(`#${nextBoxID}`).position();
// Animate each box to the other box's position
$(`#${nextBoxID}`).addClass("moving").animate({
top: currBoxPOs.top+"px",
left: currBoxPOs.left+"px"
},{
duration:animDurationMS
});
$(`#${currentBoxID}`).addClass("moving").animate({
top:nextBoxPOs.top+"px",
left:nextBoxPOs.left+"px"
},{
duration:animDurationMS
});
});
});
.wrapper{
width:100%;
height:100%;
display:flex;
flex-wrap:wrap;
justify-content:flex-start;
align-items:center;
gap:10px;
position:relative;
}
.box.moving{
/*
Tried with relative position and absolute.
Absolute position is not good because it breaks the flex flow
Sticky is my best alternative but that way just one box is moving.
Something wrong with the jquery animation queue.
*/
position:sticky;
transform:scale(0.9);
}
.box{
position:relative;
padding:10px;
width:300px;
height:300px;
border:1px solid black;
transform:scale(1);
transition: transform 0.3s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
</div>
javascript
css
object
jquery-animate
0 Answers
Your Answer