Reputation: 885
I've got a jQuery fiddle using the jQuery UI draggable to demonstrate this problem. Here is the HTML:
<div id="container">
<div id="components">
<p>
Components: Click to add a component.
</p>
<div class="component">
<div class="component-title">
One
</div>
</div>
<div class="component">
<div class="component-title">
Two
</div>
</div>
<div class="component">
<div class="component-title">
Three
</div>
</div>
</div>
<div id="workspace">
<div id="pdc">
</div>
</div>
</div>
Here is the CSS:
#workspace {
padding-top: 20px;
clear: both;
}
#pdc {
border: 1px solid #000000;
border-radius: 5px;
width: 300px;
height: 150px;
position: relative;
}
.component-title {
cursor: default;
}
#pdc .component-title {
cursor: move;
}
.component {
border: 1px solid #000000;
border-radius: 5px;
text-align: center;
width: 98px;
height: 48px;
}
#components .component {
float: left;
margin: 0 12px 0 0;
}
#pdc .component {
cursor: move;
display: inline-block;
}
.component-delete {
float: right;
color: pink;
margin-right: 5px;
cursor: pointer;
}
.component-delete:hover {
color: red;
}
Here is the jQuery:
$(document).ready(function() {
$('.component').click(function(){
var lastpdccomponent, html = $(this).clone().prepend('<div class="component-delete">X</div>');
if ($('#pdc').children().length > 0) {
lastpdccomponent = $('#pdc').children().last();
$('#pdc').append(html);
$('#pdc').children().last().position({
my: "left top",
at: "left bottom",
of: lastpdccomponent
});
} else {
$('#pdc').append(html);
}
$('#pdc .component').draggable({
containment: '#pdc',
scroll: false,
grid: [50, 50]
});
});
$('#pdc').on('click', '.component-delete', function() {
$(this).parent().remove();
});
});
It's set up so that if you click a component (One, Two, or Three), the component is cloned and added to the "pdc" div as in the image below:
If you drag the second and third components so that they are in a horizontal row with the first component:
and then delete the first component by clicking the red "X", the other components move outside the container as shown in this image:
I've experimented with other display options for the components, like "inline-block", and it fixes the issue with deleting the first in a horizontal row of components, but introduces a new problem when the first in a vertical row of components is deleted; in that case, the remaining elements move off to the left of the container.
How can I prevent the other components from moving outside the container when the first component in the row is deleted?
Upvotes: 2
Views: 915
Reputation: 624
The position
of the .component
's is relative
and thus is being calculated based on the preceding element. Once you remove the first one, the position for the follow ups is getting calculated not correctly any more. In order to prevent that behavior, just add position:absolute;
to #pdc .component{
in css to make the calculation of position of the components independent from each other, see snippet:
UPDATE I see when there is a scrollbar, positioning of the elements is getting messed up, so in order to solve this issue add collision: 'none'
to
$('#pdc').children().last().position({
my: "left top",
at: "left bottom",
of: lastpdccomponent,
collision: 'none'
});
See updated snippet:
$(document).ready(function() {
$('.component').click(function(){
var lastpdccomponent, html = $(this).clone().prepend('<div class="component-delete">X</div>');
if ($('#pdc').children().length > 0) {
lastpdccomponent = $('#pdc').children().last();
$('#pdc').append(html);
$('#pdc').children().last().position({
my: "left top",
at: "left bottom",
of: lastpdccomponent,
collision: 'none'
});
} else {
$('#pdc').append(html);
}
$('#pdc .component').draggable({
containment: '#pdc',
scroll: false,
grid: [50, 50]
});
});
$('#pdc').on('click', '.component-delete', function() {
$(this).parent().remove();
});
});
#workspace {
padding-top: 20px;
clear: both;
}
#pdc {
border: 1px solid #000000;
border-radius: 5px;
width: 300px;
height: 150px;
position: relative;
}
.component-title {
cursor: default;
}
#pdc .component-title {
cursor: move;
}
.component {
border: 1px solid #000000;
border-radius: 5px;
text-align: center;
width: 98px;
height: 48px;
}
#components .component {
float: left;
margin: 0 12px 0 0;
}
#pdc .component {
cursor: move;
position:absolute;
}
.component-delete {
float: right;
color: pink;
margin-right: 5px;
cursor: pointer;
}
.component-delete:hover {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
<div id="container">
<div id="components">
<p>
Components: Click to add a component.
</p>
<div class="component">
<div class="component-title">
One
</div>
</div>
<div class="component">
<div class="component-title">
Two
</div>
</div>
<div class="component">
<div class="component-title">
Three
</div>
</div>
</div>
<div id="workspace">
<div id="pdc">
</div>
</div>
</div>
Upvotes: 1
Reputation: 42354
The problem is that on click of .component-delete
, the components don't get 'reset' to their default positions, and have an inline height
of -50px
(and a left
offset).
You can resolve this by resetting their positions manually, adding:
$(this).parent().siblings().css('top', '0');
$(this).parent().siblings().css('left', '0');
To the deletion function, resulting in the following:
$('#pdc').on('click', '.component-delete', function() {
$(this).parent().siblings().css('top', '0');
$(this).parent().siblings().css('left', '0');
$(this).parent().remove();
});
This will make the second and third element move two the left and stack vertically when deleting the first element, as can be seen working here.
Unfortunately I don't think it's possible to keep the remaining two elements in a horizontal line on deletion, as if you omit resetting the height
position, the second element would take on the height
offset from the first. Hopefully this is still sufficient.
Hope this helps! :)
Upvotes: 0
Reputation: 12601
Set you .component
to position: absolute;
and this should fix it since your container #pdc
is already set to position: relative;
. When you delete the element that the others are positioned relative off of everything goes crazy, but when they are absolutely positioned they should stay put.
Also set the #components .component
to position: static;
because you don't need those positioned.
See this fiddle for a demo
CSS Changes:
.component {
position: absolute; /*Add this*/
border: 1px solid #000000;
border-radius: 5px;
text-align: center;
width: 98px;
height: 48px;
}
#components .component {
position: static; /*Add this*/
float: left;
margin: 0 12px 0 0;
}
Upvotes: 1