I am creating a set of stacked elements where one element could be added on top and the rest will move down. Likewise, an element can be delete and every element beneath this one will slide up. However, I am struggling a bit with the animation part.
I managed to set the animations and the divs slide up and down. However, when the class ‘transitionUp’ is added (this happens after adding/removing/moving a div), if I add/remove several rows quickly that messes up the animation. If I wait for the transition to finish between actions, then it works fine. I wonder if there is a better way of doing this.
I created a snippet to explain the problems I am having:
for (var i = 0; i < 3; i++) {
addMore(i);
}
$('#addMoreBtn').click(function() {
addMore($('#previewDivContainer').children().length)
});
function moveDivToTop(elm) {
var index = $(elm).index();
$('#previewDivContainer').children().slice(0, index).each(function () {
moveDivDown(this);
});
$(elm).css('margin-top', "0px");
$(elm).prependTo($('#previewDivContainer'))
};
function moveDivUp(index) {
$('#previewDivContainer').children().slice(index, $('#previewDivContainer').children().length).each(function () {
$(this).addClass("transitionUp");
$(this).css('margin-top', parseFloat($(this).css('margin-top')) - $($('#previewDivContainer').children()[0]).height() + "px");
});
};
function moveDivDown(elm) {
$(elm).addClass('transitionUp');
$(elm).css('margin-top', parseFloat($(elm).css('margin-top')) + $($('#previewDivContainer').children()[0]).height() + "px");
};
function removeDiv(elm) {
var index = $(elm).index();
console.log(index)
moveDivUp(index);
elm.remove();
};
function addMore(index) {
$('#previewDivContainer').prepend(
$('<div>', { class: "previewDiv"}).append(
$('<span>', { class: "previewDivName", text: index}),
$('<span>', { class: "previewDivMesage", text: `This is ${index}`}),
$('<div>').append(
$('<button>', {class: "btnUpd", text: "↑"}).click(function () {moveDivToTop($(this).closest('.previewDiv'))}),
$('<button>', {class: "btnDown", text: "X"}).click(function () {removeDiv($(this).closest('.previewDiv'))}),
)
)
)
moveManyDown(0);
};
function moveManyDown (index) {
$('#previewDivContainer').children(`:gt(${index})`).each(function() {
$(this).css('margin-top', parseFloat($(this).css('margin-top')) + $($('#previewDivContainer').children()[0]).height() + "px");
})
}
.previewDiv {
width: 100px;
height: 55px;
font-size: 13px;
border: 1px solid black;
position: absolute;
}
#previewDivContainer {
position: relative;
}
.previewDivMesage {
display: block;
white-space: nowrap;
}
#addMoreBtn {
margin-left: 200px;
margin-top: 10px;
}
.transitionUp {
transition: margin-top 1s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div id="previewDivContainer">
</div>
<div id='addMore'>
<button id='addMoreBtn'>
Add More
</button>
</div>
2
Answers
Thanks to @green-21 for pointing me in the right direction. I am only writting this to include a full snippet in case it can be useful to somebody reading this.
The reason is that the margin values change during animantion.
so, solution is to use fixed value when set margin.
The margin is determined by the position of the element.
rewrite like this,