we trying to integrate multiple drggable and droppable. we are using sortable for ease of clone functionality in this scenario. draggable once dropped need to be draggable again.
how do we limit sortable to receive only one element and revert to original if more than one dropped onto it.
look like out and over functions of sortable are misbehaving in that case.
commented line code is for disabling dropping second element on sortable. which is not working as expected.
Two issues when you enable my commented code:
draggable clone not reverting to original place after moving out of droppable.
draggable element moved from one droppable to another reverting to draggable's original place.
For a demonstration, see this jsfiddle
script:
// jQuery.noConflict();
jQuery( document ).ready(function() { init();});
function init() {
var mouse_button = false;
jQuery('.ui-draggable').live({
mousedown: function () {
mouse_button = true;
},
mouseup: function () {
if (jQuery(this).attr('data-pos') == 'out' && jQuery(this).attr('data-id')) {
var p = jQuery('#' + jQuery(this).attr('data-id'));
var offset = p.offset();
jQuery(this).hide();
jQuery(this).animate({ left: offset.left, top: offset.top, width: jQuery(this).width, height: jQuery(this).height }, 100, function () {
jQuery(this).remove();
$( ".ui-droppable" ).each(function() {
if($(this).children().length == 0) {
$( this ).removeClass("dontDrop");
}
});
//if(p[0].hasAttribute("draggable"))
p.draggable("enable");
// $('.ui-droppable').sortable('option', 'connectWith',$('.ui-droppable').not('.dontDrop'));
// $('.ui-draggable').draggable('option', 'connectToSortable',$('.ui-droppable').not('.dontDrop'));
});
}
mouse_button = false;
},
mouseout: function () {
if (mouse_button) {
mouse_button = false;
}
}
});
jQuery( '.ui-draggable' ).draggable( {
cursor: 'move',
helper: 'clone',
connectToSortable: ".ui-droppable",
revert: function (event, ui) {
}
} );
jQuery(".ui-droppable").sortable({
cursor: "move",
connectWith: ".ui-droppable",
receive: function (event, ui) {
if($(this).children().length >= 1) {
$(this).children().addClass('filled');
$(this).addClass('dontDrop');
$( ".ui-droppable" ).each(function() {
if($(this).children().length == 0) {
$( this ).removeClass("dontDrop");
}
});
// $('.ui-droppable').sortable('option', 'connectWith',$('.ui-droppable').not('.dontDrop'));
// $('.ui-draggable').draggable('option', 'connectToSortable',$('.ui-droppable').not('.dontDrop'));
}else {
$(this).children().removeClass('filled');
}
if (jQuery(this).data().sortable.currentItem) {
jQuery(this).data().sortable.currentItem.attr('data-id', jQuery(ui.item).attr("id"));
// if(jQuery(ui.item)[0].hasAttribute("draggable"))
jQuery(ui.item).draggable("disable");
}
},
out: function (event, ui) { if (ui.helper) { ui.helper.attr('data-pos', 'out'); } },
over: function (event, ui) { ui.helper.attr('data-pos', 'in'); }
});
}
Here's a working example: click here
You can user Jquery's draggable and droppable interactions to achieve what you want. Check the working example.
$(document).ready(function () {
$(".ui-draggable").draggable(draggable_options) //make cards draggable
$(".ui-droppable").droppable({ //handle card drops
greedy: true,
drop: function (event, ui) {
handleDrop(this, event, ui)
},
accept: function () {
return checkIfShouldAcceptTheDraggable(this)
}
})
})
You can do it like this:(Online Demo (fiddle))
var draggable_options = {
helper: 'clone',
cursor: 'move',
revert: 'invalid',
};
$(".ui-draggable").draggable(draggable_options);
$(".ui-droppable").droppable({
drop: function(event, ui) {
var $item = ui.draggable;
$item.draggable(draggable_options)
$item.attr('style', '')
$(this).append($item)
},
accept: function() {
return $(this).find("li").length === 0 // Your condition
}
});
$(".textToImageRightPanel").droppable({
drop: function(event, ui) {
var $item = ui.draggable;
$item.draggable(draggable_options);
$item.attr('style', '');
// Return to older place in list
returnToOlderPlace($item);
}
});
// Return item by drop in older div by data-tabidx
function returnToOlderPlace($item) {
var indexItem = $item.attr('data-tabidx');
var itemList = $(".textToImageRightPanel").find('li').filter(function() {
return $(this).attr('data-tabidx') < indexItem
});
if (itemList.length === 0)
$("#cardPile").find('ul').prepend($item);
else
itemList.last().after($item);
}
Determining when to revert may be best done in .draggable() using revert: function(){}.
Function: A function to determine whether the element should revert to its start position. The function must return true to revert the element.
You can do this:
jQuery('.ui-draggable').draggable({
cursor: 'move',
helper: 'clone',
connectToSortable: ".ui-droppable",
revert: function(item) {
if (!item) {
return true;
} else {
if (item.hasClass("dontDrop")) {
return true;
}
}
return false;
}
});
the revert function is passed false if the draggable item is not accepted. For example, if it is dropped on something that is not a target. If the draggable item is accepted, a jQuery Object is passed back.
See more: jQueryUI sortable,draggable revert event
The logic is a little confusing. If what is passed back is false, we return true to revert letting draggable revert the item to it's position. If what is passed back is not false, then it's an object we can test. If the target is "full", we revert. Otherwise we do not revert.
Sortable still wants add the item for some reason. May need to adjust to update and clear out any items that are not class "filled".
Fiddle: https://jsfiddle.net/Twisty/7mmburcx/32/
Related
I have 2 divs: leftDiv and mainDiv. leftDiv contains some list elements which are draggable and droppable into mainDiv. I want to make these dropped items draggable inside the mainDiv as well, but after the first drag inside this div, items become non draggable. How can I fix this? Here is my jQuery code:
$('#output li').draggable({
helper: 'clone',
revert: 'invalid'
});
$('#mainDiv').droppable({
drop: function (event, ui) {
if(ui.draggable.hasClass('foo')){
$(ui.helper).remove();
$(this).append(ui.draggable.draggable());
}
else {
var item = $('<div class="foo">').append(ui.draggable.text());
item.draggable();
$(this).append(item);
}
}
});
You can fix it like this:
$('#mainDiv').droppable({
drop: function (event, ui) {
if(ui.draggable.hasClass('foo')){
//$(ui.helper).remove();
var draggedItem = ui.draggable.draggable();
$(this).append(draggedItem);
draggedItem.draggable();
}
else {
var item = $('<div class="foo">').append(ui.draggable.text());
item.draggable();
$(this).append(item);
}
}
});
Online Demo (fiddle)
I have number of drop areas $('.drophere') and a storage of draggables $('.dragme').
Each drop area can contain just one dropped item.
You can drop new item over dropped one (replace). You can drag an item from one drop area to other.
If you start drag an item from drop area and decided drop it back to same area - drop event is not fired, thus the dragged item is lost.
Here is simplified code:
var draggedData;
$('.drophere').droppable({
drop: function (event, ui) {
$(this).attr('data-text', draggedData);
$(this).draggable('enable');
}
}).draggable({
disabled: true,
helper: "clone",
start: function (event, ui) {
draggedData = $(this).attr('data-text');
$(this).attr('data-text', "").draggable('disable');
}
});
$('.dragme').draggable({
helper: "clone",
start: function (event, ui) {
draggedData = $(this).attr('data-text');
}
});
Is it some kind of restriction in jQuery UI droppable? Is any way to "forget" the origins of such dragged item? Thank you.
just added: http://jsfiddle.net/gpnpwwbw/
Taking advantage of jQuery Draggables Stop event I came up with the following solution:
var draggedData,
dropLastDragged
startPosData = {};
function checkIntersect(posData){
var left = startPosData.left,
top = startPosData.top,
right = startPosData.left+startPosData.width,
bottom = startPosData.top+startPosData.height,
cornerLeftPos = posData.left,
cornerTopPos = posData.top;
cornerLeftPos += startPosData.width/2;
cornerTopPos += startPosData.height/2;
if((cornerLeftPos > left && cornerLeftPos < right) && (cornerTopPos > top && cornerTopPos < bottom)){
return true;
}
return false;
}
$('.drophere').droppable({
drop: function (event, ui) {
dropLastDragged = false;
$(this).html(draggedData);
$(this).draggable('enable');
}
}).draggable({
disabled: true,
helper: "clone",
start: function (event, ui) {
startPosData.left = ui.offset.left;
startPosData.width = $(this).width();
startPosData.top = ui.offset.top;
startPosData.height = $(this).height();
draggedData = $(this).html();
$(this).html('Drop here').draggable('disable');
dropLastDragged = this;
},
stop: function(event, ui) {
if(dropLastDragged){
if(checkIntersect(ui.offset)){
$(dropLastDragged).html(ui.helper.html());
$(dropLastDragged).draggable('enable');
}
}
}
});
$('.dragme').draggable({
helper: "clone",
start: function (event, ui) {
draggedData = $(this).html();
}
});
Fiddle
im trying to develop a game using jquery drag and drop and need help on it. The problem i am facing is that there are 4 drop location and about 25 dragable elements. Each drop location can have only one draggable element and if i try to drop another element the location should be swapped and previously dropped element will get the initial location of newly dragged element.
$(".drag").draggable({
containment: ".dropable",
revert: "invalid",
appendTo: '.dropable',
start: function (evt, ui) {
if (!ui.helper.data("originalPosition")) {
ui.helper.data("originalPosition", ui.originalPosition)
}
}
});
$(".debit_option").droppable({
greedy: true,
accept: '.drag',
over: function () {
$(this).removeClass('out').addClass('hoverClass')
},
out: function () {
$(this).removeClass('hoverClass').addClass('out')
},
drop: function (event, ui) {}
});
$(".credit_option").droppable({
over: function () {
$(this).removeClass('out').addClass('hoverClass')
},
out: function () {
$(this).removeClass('hoverClass').addClass('out')
},
drop: function (event, ui) {}
})
});
function revertDraggable($selector) {
$selector.each(function () {
var $this = $(this);
console.log($this.data('originalPosition'));
position = $this.data('originalPosition');
if (position) {
$this.animate({
left: position.left,
top: position.top
}, 500, function () {
$this.data("orignalPosition", null)
})
}
})
}
$(".no_entry a").click(function (e) {
e.preventDefault();
revertDraggable($(".drag"))
});
I will simplify my explanation so you get what I am doing. I have two div's and I set up portlets as shown here, however I am dynamically injecting my portlets, no big problem there.
<div id="mainallapplicant" class="myrow"></div>
<div id="contingent_right" class="myrow"></div>
Here is the JavaScript
$( ".myrow" ).sortable({
connectWith: ".myrow",
revert: true,
beforeStop: function( event, ui ) {}
});
I am trying to allow a maximum of only one droppable into mainallapplicant. If there is one already there, I will show a confirmation dialog and depending on the answer, I cancel the drop or move out the existing item and replace it with the new item. I tried the following but I am getting nowhere.
$( ".myrow" ).sortable({
connectWith: ".myrow",
revert: true,
start: function(event, ui) {
if ($(this).prev().find(".portlet").length == 1) {
ui.sender.draggable("cancel");
}
},
stop: function(event, ui) {
if ($(this).prev().find(".portlet").length == 1) {
ui.item.remove();
// Show an error...
}
}
});
You can use start to get the current count of portlet elements, then use stop to do the checking
Also notice I added class names to each div to allow only one div to have a maximum of 1 portlet
$(document).ready(function () {
$.count = 0;
$(".myrow").sortable({
connectWith: ".myrow",
revert: true,
start: function () {
$.count = $(".myrow").has(".portlet").length;
console.log("Start " + $.count);
},
stop: function (event, ui) {
if ($(ui.item).parent(".myrow").hasClass("left")) {
if ($.count == 2) {
$(".myrow").sortable("cancel");
}
}
}
});
});
DEMO: http://jsfiddle.net/Ue4dq/
I have a jQuery plugin that drags and drops elements into different containers, I want to attach some events, for example when an element is over a container. These events used to work perfectly but then they stopped working. for Some reason the Selectable specific events are not fired, but when i bind a click for example it works.
Example:
//these are not working
$('#sortable2').bind("sortover", function(event, ui) {
alert("here");
});
$('#sortable2').bind('sortreceive', function() {
alert('User clicked on "sortable2."');
});
$('.droptrue').bind("sortout", function(event, ui) {
$(this).css("background", "transparent");
});
The related code is:
var selectedClass = 'ui-state-highlight',
clickDelay = 300, // click time (milliseconds)
lastClick, diffClick; // timestamps
$("ul.droptrue li")
// Script to deferentiate a click from a mousedown for drag event
.bind('mousedown mouseup', function(e){
if (e.type=="mousedown") {
lastClick = e.timeStamp; // get mousedown time
} else {
diffClick = e.timeStamp - lastClick;
if ( diffClick < clickDelay ) {
// add selected class to group draggable objects
$(this).toggleClass(selectedClass);
}
}
})
.draggable({
revertDuration: 10, // grouped items animate separately, so leave this number low
containment: '.multiSelect',
start: function(e, ui) {
ui.helper.addClass(selectedClass);
},
stop: function(e, ui) {
// reset group positions
$('.' + selectedClass).css({ top:0, left:0 });
},
drag: function(e, ui) {
// set selected group position to main dragged object
// this works because the position is relative to the starting position
$('.' + selectedClass).css({
top : ui.position.top,
left: ui.position.left
});
}
});
$("ul.droptrue")
.sortable()
.droppable({
drop: function(e, ui) {
$('.' + selectedClass)
.appendTo($(this))
.add(ui.draggable) // ui.draggable is appended by the script, so add it after
.removeClass(selectedClass)
.css({ top:0, left:0 });
}
});
$('#total').text(autoCompleteSourceArray.length);
$('#filter-count').text(autoCompleteSourceArray.length);
//Adding Filtering functionality for the lists
$("#filter").keyup(function () {
var filter = $(this).val(), count = 0;
$("ul.droptrue:first li").each(function () {
if ($(this).text().search(new RegExp(filter, "i")) < 0) {
$(this).addClass("hidden");
} else {
$(this).removeClass("hidden");
count++;
}
});
$("#filter-count").text(count);
});
// bind events in order to show or hide the message in the drop zones
$('ul[id^="sortable"]').live("sortover", function(event, ui) {
$(this).css("background", "#f7f6d7");
});
$('ul[id^="sortable"]').live("sortout", function(event, ui) {
$(this).css("background", "transparent");
});
Thanks a lot
If you have recently updated to jQuery 1.7+ you should notice that the live() method is deprecated.
As of jQuery 1.7, the .live() method is deprecated. Use .on() to
attach event handlers. Users of older versions of jQuery should use
.delegate() in preference to .live().