Reputation: 8930
I've been trying out JqueryUI for a simple task where I need to implement a basic drag and drop feature. I noticed that when I use the snap to grid option, the elements aren't aligned properly when they are being dropped to the target container. It calculates the position of the draggable element from within its container although I defined the containment to be the target area.
see a sample code here: https://jsfiddle.net/9yzL87md/7/
$( function() {
$( ".spare-item" ).draggable({
grid: [ 26, 26 ],
containment: "#preview",
cursor: "grab",
revert: "invalid",
start: function( event, ui ) {
console.log(ui);
console.log(ui);
}
});
$( "#preview" ).droppable({
accept: ".spare-item",
over: function(event, ui) {
$(".spare-item").draggable({
grid: [26, 26]
});
},
out: function(event, ui) {
$(".spare-item").draggable("option", "grid", false);
},
drop: function( event, ui ) {
var pos = ui.draggable.offset(), dPos = $(this).offset();
//console.log(pos.top - dPos.top, pos.left - dPos.left);
}
});
} );
above is a sample of my layout for easier understanding. If you try to drag the red element, it will immediately take that into the grey box, but will be snapped a little bit lower than the lower border. I tried many of the similar questions and solutions, but had no luck. What am I missing here? (the width of the container is 234px, and the width of red elements are 26px. I expect the red elements to be snapped in a 26 x 26 grid)
Upvotes: 0
Views: 1793
Reputation: 2643
The issue your having is due to the padding and margin in the actions
, item-container
and the spare-item
classes. Setting margin and padding to zero in these classes fixes the issue. e.g.
.actions{
width: 234px;
margin: 0px auto;
padding: 0px; /*Updated*/
}
.item-container{
height: 26px;
margin: 0px auto; /*Updated*/
}
.spare-item{
background: red;
display: inline-block;
width: 26px;
height: 26px;
margin: 0px 0px; /*Updated*/
}
The jquery is not accounting for the padding and margin between the #preview
and the actions item-container
divs when calculating the position offsets which is causing it to snap to the grid with a top gap same as the gap between the 2 containers. So in order to fix this please see the section 'Edit for Solution' below:
[Edit for Solution]
Just to update for a solution to everyone on this. You need to use the snap
option and set it's value to the grid element within the item's draggable function. e.g. in order to fix your fiddle just add this snap
property in the spare-items
draggable method options as follows:
$( ".spare-item" ).draggable({
grid: [ 26, 26 ],
containment: "#preview",
cursor: "grab",
revert: "invalid",
start: function( event, ui ) {
console.log(ui);
console.log(ui);
},
snap: '#preview' // removes any margin or padding from the item
});
Hope this helps you and all who are experiencing this issue. Happy Coding. :)
Upvotes: 1
Reputation: 1153
you have multiple issues here. the draggable elements are still in the lower div, and affected by margins and paddings, which offsets them relative do your .item-container. finally, because they are inline-block elements (as opposed to block elements) the whitespace BETWEEN TAGS causes there to be an empty space between the elements. Either you turn them into block elements, or there cannot be any whitespace between the spare-item div tags.
The grid seems to be offset by the original item position, so offset spare-item's have an offset grid.
Result: https://jsfiddle.net/9yzL87md/10/
neither .output, .actions or .item-container can have margins or paddings that affect the spare-items.
.output{
background:#646464;
# padding: 5px; removed
}
.actions{
width: 234px;
margin: 0px auto;
# padding: 5px; removed
}
.item-container{
height: 26px;
margin: 0px auto; #no vertical
}
.spare-item{
background: red;
display: inline-block;
width: 26px;
height: 26px;
margin: 0 0; # no horizontal margin
}
inline-block elements have a space between them if there is ANY whitespace at all (space, tab, newline). so either make the spare-item elements display: block or remove the whitespace between them with any variation of the following:
<div class="actions item-container"><!--
--><div class="spare-item"></div><!--
--><div class="spare-item"></div><!--
--><div class="spare-item"></div><!--
-->
or one of the other tricks described here https://css-tricks.com/fighting-the-space-between-inline-block-elements/
in case the link dies, the options listed are:
Upvotes: 1