Only allowing one droppable area jquery drag and drop - javascript

I have jquery drag and drop working so I can move one row in a table to another.
the demo is here:
http://www.aussiehaulage.com.au/Default.aspx
I use jquery-ui-1.8.22 to make my table draggable/droppable.
My javascript is :
$(document).ready(function () {
$(".draggable").draggable({
helper: function () { return "<div class='ghost'></div>"; },
start: resizeGhost,
revert: 'invalid'
});
$(".droppable").droppable({
hoverClass: 'active',
drop: function (event, ui) {
var target = $(event.target);
var draggable = ui.draggable;
draggable.insertBefore(target);
},
tolerance: 'touch'
});
});
However when i move the row, if the mouse cursor is in between 2 rows on the droppable table both droppable rows are highlighted.. I need to make it so it will only highlight 1 droppable row at a time..
is this possible?

Add a new option in your droppable element, using either tolerance fit or intersect
$(".droppable").droppable({
hoverClass: 'active',
tolerence: 'intersect',
drop: function (event, ui) {
var target = $(event.target);
var draggable = ui.draggable;
draggable.insertBefore(target);
},
tolerance: 'touch'
});
And for your reference: jquery-ui

Related

Create Drag & Drop, Destory, Save Re-create - jQuery

Ok, I have an issue with drag and drop.
What they do, they click a button, it initializes the whole drag and drop.
function sortElements() {
// Place droppable elements
var x = 0;
$("#content-body div[data-type='column'],#content-body div[data-type='carousel']").each(function() {
var el = $(this);
if(x == 0){
el.before('<div class="neoDroppableEle" id="neoDroppableEle-' + x + '"><\/div>');
x++;
}
el.addClass('edit_el').after('<div class="neoDroppableEle" id="neoDroppableEle-' + x + '"><\/div>');
x++;
el.append('<div class="drag-handle"><i class="fa fa-arrows"></i></div>');
var w = el.width();
el.css('width',w+'px');
});
$("#content-body div[data-type='insertable']").each(function() {
var el = $(this);
el.prepend('<div class="neoDroppableEle" id="neoDroppableEle-' + x + '"><\/div>');
x++;
});
// Swap entire columns
$("#content-body div[data-type='column']").draggable({
refreshPositions: true,
helper: "clone",
handle:'.drag-handle',
appendTo: "body",
zIndex: 10000,
start: function( event, ui ) {
$(".neoDroppableEle").addClass('dragging');
},
stop: function( event, ui ) {
$(".neoDroppableEle").removeClass('dragging');
}
});
$(".neoDroppableEle").droppable({
accept: "div[data-type='column']",
tolerance: "pointer",
hoverClass: "focus_in",
activeClass: "focus_in_active",
drop: function(event, ui) {
cur_ele = this.id;
var el = ui.draggable;
var html = el.html();
el.remove();
$("#" + cur_ele).replaceWith('<div class="row" data-type="column">'+html+'</div>');
}
});
// Swap individual photos within columns
$("#content-body div[data-type='imagewrap']").each(function(){
$(this).draggable({
revert: "invalid",
helper: "clone" ,
zIndex: 10001,
});
$(this).droppable({
accept: "div[data-type='imagewrap']",
activeClass: "ui-state-hover",
hoverClass: "ui-state-active",
drop: function( event, ui ) {
var draggable = ui.draggable, droppable = $(this);
draggable.swap(droppable);
}
});
});
}
When they are done, they click the button again.
function sortElementsComplete() {
$(".ui-droppable").droppable("destroy");
$(".ui-draggable").draggable("destroy");
$(".edit_el").removeAttr('style').removeClass('edit_el');
$(".neoDroppableEle").remove();
$(".drag-handle").remove();
}
This all runs and works great!
But now I am tryng to save the HTML code after each drop for undo's. And when I save the undo, I need to remove all additional classes and elements my function to drag and drop add's. Because they may not be in the sorting area when they click undo and do not want drag handles and my borders I set up as visual aids just appearing.
So now I have:
$(".neoDroppableEle").droppable({
accept: "div[data-type='column']",
tolerance: "pointer",
hoverClass: "focus_in",
activeClass: "focus_in_active",
drop: function(event, ui) {
cur_ele = this.id;
var el = ui.draggable;
var html = el.html();
el.remove();
$("#" + cur_ele).replaceWith('<div class="row" data-type="column">'+html+'</div>');
setTimeout(function(){
sortElementsComplete();
editor_add();
},1000);
}
});
The above with the timeout code always fails with:
Error: cannot call methods on droppable prior to initialization;
attempted to call method 'destroy'
How so? It IS initialized and running. After the drop I should be able to destroy it, make my save and rebuild it. Using disable gives the same error. To me the error makes no sense.
After editor_add() is ran, it re-builds whatever they were doing, in this case it will fire sortElements(); after the save.
But the below runs fine?
// Swap individual photos within columns
$(this).droppable({
accept: "div[data-type='imagewrap']",
activeClass: "ui-state-hover",
hoverClass: "ui-state-active",
drop: function( event, ui ) {
var draggable = ui.draggable, droppable = $(this);
draggable.swap(droppable);
setTimeout(function(){
sortElementsComplete();
editor_add();
},250);
}
});
It will error if I do not have the timeout above. Seems 250 is the min, anything lower it errors. But the first one will not ever work, no matter how long or short I make the timeout.
Really hope this makes sense.
Maybe if I used
var draggable = ui.draggable, droppable = $(this);
draggable.swap(droppable);
On it instead it would work. o.O

Dropping a draggable in a droppable at the drop position

I have been trying to clone and drop a draggable at the position in a droppable at the coordinates where the drop happens. I have found examples online that deal with appending draggables to droppables, but they all seem to move the draggable to a specific part of the droppable on the initial drop.
Here is an example that does just that: - http://jsfiddle.net/scaillerie/njYqA/
//JavaScript from the jsfiddle
jQuery(function() {
jQuery(".component").draggable({
// use a helper-clone that is append to 'body' so is not 'contained' by a pane
helper: function() {
return jQuery(this).clone().appendTo('body').css({
'zIndex': 5
});
},
cursor: 'move',
containment: "document"
});
jQuery('.ui-layout-center').droppable({
activeClass: 'ui-state-hover',
accept: '.component',
drop: function(event, ui) {
if (!ui.draggable.hasClass("dropped"))
jQuery(this).append(jQuery(ui.draggable).clone().addClass("dropped").draggable());
}
});
});
Is there anyway I can make the draggable stay at the coordinates where the drop occured?
you must define the coordinates in the cloned element on the drop:
drop: function(event, ui) {
if (!ui.draggable.hasClass("dropped"))
var clone=jQuery(ui.draggable).clone().addClass("dropped").draggable();
clone.css('left',ui.position.left);
clone.css('top',ui.position.top);
jQuery(this).append(clone);
}
});
and also set the position absolute by css on the cloned components
.ui-layout-center .component {
position:absolute !important;
}
Here is working: http://jsfiddle.net/o2epq7p2/
Edited you code and used appendTo() and set the offset
jQuery(function() {
jQuery(".component").draggable({
// use a helper-clone that is append to 'body' so is not 'contained' by a pane
helper: function() {
return jQuery(this).clone().appendTo('body').css({
'zIndex': 5
});
},
cursor: 'move',
containment: "document"
});
jQuery('.ui-layout-center').droppable({
activeClass: 'ui-state-hover',
accept: '.component',
drop: function(event, ui) {
var _this = jQuery(this);
if (!ui.draggable.hasClass("dropped")) {
var cloned = jQuery(ui.draggable).clone().addClass("dropped").draggable();
jQuery(cloned).appendTo(this).offset({
top : ui.offset.top,
left: ui.offset.left
});
}
}
});
});
ui in the drop handler contains the dragged element's position absolute to the page. You need to transform those values to a position relative to the drop target and absolute position the cloned element inside the drop target using these values.
drop: function(e, ui) {
if (!ui.draggable.hasClass("dropped")) {
var parentOffset = jQuery('.ui-layout-center').offset();
var dropped = jQuery(ui.draggable).clone().addClass("dropped").draggable();
dropped.css('left', (ui.position.left - parentOffset.left) +'px');
dropped.css('top', (ui.position.top - parentOffset.top) +'px');
jQuery(this).append(dropped);
}
}
http://jsfiddle.net/3Lnqocf3/

Sortable, droppable nested list issue [duplicate]

I'm working on a project where I'm dragging elements from a 3rd party jQuery control to a jQuery sortable, using a combination of droppable and sortable.
This works perfectly fine, except the item being added is always added to the bottom of the sortable list, and you must then move it to the correct location as a separate step.
Is it possible to have the item added to the location where you dropped it in the list?
You can see this behavior in the jQuery shopping card droppable demo from here. Here is a jsfiddle of the same code. As you add items from the products to your cart at the bottom, it always adds at the bottom, even if you drop it near the top.
Here's the jQuery code:
$(function () {
$("#catalog").accordion();
$("#catalog li").draggable({
appendTo: "body",
helper: "clone"
});
$("#cart ol").droppable({
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
accept: ":not(.ui-sortable-helper)",
drop: function (event, ui) {
$(this).find(".placeholder").remove();
$("<li></li>").text(ui.draggable.text()).appendTo(this);
}
}).sortable({
items: "li:not(.placeholder)",
sort: function () {
$(this).removeClass("ui-state-default");
}
});
});
use droppable's drop event's callback to compare the current top offset position of the draggable helper with the top offset of every element already present or previously added in the droppable
drop: function (event, ui) {
if($(this).find(".placeholder").length>0) //add first element when cart is empty
{
$(this).find(".placeholder").remove();
$("<li></li>").text(ui.draggable.text()).appendTo(this);
}
else
{
var i=0; //used as flag to find out if element added or not
$(this).children('li').each(function()
{
if($(this).offset().top>=ui.offset.top) //compare
{
$("<li></li>").text(ui.draggable.text()).insertBefore($(this));
i=1;
return false; //break loop
}
})
if(i!=1) //if element dropped at the end of cart
{
$("<li></li>").text(ui.draggable.text()).appendTo(this);
}
}
}
DEMO WITH CODE
FULL SCREEN DEMO
What about doing this? Using both the connectToSortable AND connectWith options works, I think. There might be a more clever way to hide/show the placeholder, but this definitely works.
$(function () {
$("#catalog").accordion();
$("#catalog li").draggable({
appendTo: "body",
helper: "clone",
connectToSortable: "#cart ol"
});
$("#cart ol").sortable({
items: "li:not(.placeholder)",
connectWith: "li",
sort: function () {
$(this).removeClass("ui-state-default");
},
over: function () {
//hides the placeholder when the item is over the sortable
$(".placeholder").hide();
},
out: function () {
if ($(this).children(":not(.placeholder)").length == 0) {
//shows the placeholder again if there are no items in the list
$(".placeholder").show();
}
}
});
});
Work Demo in Fiddle

Angular Sortable Containment prevents drop operation

I have a horizontal sortable Angular list but the containment option doesn't work and actually prevents the dragged item from being dropped.
Here's the sortable list without a containment option - notice that you have to "shake" the boxes to make them drop sometimes:
http://jsfiddle.net/zobgawqt/
$scope.sortableOptions = {
tolerance: 'pointer',
update: function(event, ui) { alert(ui.item.index()); }
};
Here's the sortable list WITH a containment option:
http://jsfiddle.net/4b4jzycs/2/
$scope.sortableOptions = {
containment: 'parent',
tolerance: 'pointer',
update: function(event, ui) { alert(ui.item.index()); }
};
Notice in the second version that the boxes are draggable but not droppable.
Here's a jQuery version that works with the same containment option:
http://jsfiddle.net/L7jemdbh/
Looks like the containment property needs a common ancestor of all the sortable items. If you give it a selector of the .sort-container node, it works as expected:
$scope.sortableOptions = {
containment: '.sort-container',
tolerance: 'pointer',
update: function(event, ui) { alert(ui.item.index()); }
};
Updated Fiddle
This is the simplest example I could create that works:
http://jsfiddle.net/0sx1wnyr/1/
There is a fix for the problem with having to shake the block to drop it - you need to add a 'start' event handler:
https://github.com/angular-ui/ui-sortable/issues/19
$scope.sortableOptions = {
containment: "parent",
axis: "x",
tolerance: "pointer",
start: function(e, ui) {
$(e.target).data("ui-sortable").floating = true;
}
};

jQuery - drag and drop of cloned element

I have a cloned element which I am able to drag however I wish to drop it in a specific div element and if valid not revert back to its original position, however it is always reverting back to its original position whether it is valid or not.
I am currently using the code below:
$("ul#objectsList li").draggable({
revert: 'invalid',
snap: "#objectsDropBox",
snapMode: "inner",
helper: function() { return $(this).clone().appendTo('body').show(); },
start: function(e, ui) { $(ui.helper).addClass("ui-draggable-helper");}
});
$("#objectsDropBox").droppable({
accept: "ul#objectsList li",
drop: function( event, ui ) {
alert('hi');
}
});
Why is it not staying in the div when a valid draggable is dropped?
Try this
$("#objectsDropBox").droppable({
accept: "ul#objectsList li",
drop: function (event, ui) {
$(this).append(ui.draggable);
//if you want to retain the element use ui.draggable.html() or clone it.
}
});
Fiddle - http://jsfiddle.net/dmNhZ/

Categories

Resources