I'm working on an app that requires drag-drop. Upon drop, the selected draggable needs to remain present but become disabled. Then the new 'dropped' item is appended with a 'close' button. Upon clicking the close button, the item disappears from the 'droppable' area and re-activates as a draggable.
The issue is that once I disable the draggable (after successful drop), i cannot re-enable that one unique item in my separate 'remove' function. here's some sample code - alot of it is stripped out for purposes of simplicity in hopes of getting advice on this particular issues i'm having.
// DROP: initiate droppables
$(".droppable").droppable({
hoverClass: 'drag-state-hover',
accept: '.draggable li img',
tolerance: 'fit',
drop: function(event, ui) {
var elementID = $(ui.draggable).attr("id") // get the dynamically set li id for each list item chosen
if( $(this).children('img').attr('src') == 'images/elements/blank.gif' ) {
// disable the element once it's been dragged and dropped
$(ui.draggable).draggable( 'option', 'disabled', true );
// turn on the remove link
$(this).find('a.remove').toggle();
}
}
});
// ITEM REMOVE: function for removing items
$('.remove').click(function(e) {
var targetID = $(this).parent('li').attr('id');
$('#' + targetID).children('img').draggable( 'option', 'disabled', false );
e.preventDefault();
});
I've also tried this with no success...
// ITEM REMOVE: function for removing items
$('.remove').click(function(e) {
var targetID = $(this).parent('li').attr('id');
$(".droppable").droppable({
hoverClass: 'drag-state-hover',
accept: '.draggable li img',
tolerance: 'fit',
drop: function(event, ui) {
$(ui.draggable).draggable( 'option', 'disabled', false );
}
});
e.preventDefault();
});
I've spent days searching on google for a solution, but I'm banging my head at this point. any assistance would be much appreciated. Thanks!!
Rather than using .draggable( 'option', 'disabled', false ); you can use .draggable( 'enable' );. I don't know if that will solve your problem, but that's how I'd start with debugging it.
In your remove function, have you tried to re-instantiate the element as a draggable? $('#' + targetID).children('img').draggable{}
Related
I know I'm missing something very basic, but when using jQuery in a situation where you have stacked "droppable" DIVs on top of each other (think nested boxes), how do you allow and accept an element drop on the top most DIV and then cancel the drag/drop event so it is not also sent to the other "droppable" DIVs below?
$('#'+objectID+" .task-droppable").droppable({
accept: function(d) {
if(d.hasClass("source-task")||d.hasClass("source-sequence")){ //sequences can contain both sequences and tasks
return true;
} //end if
}, //end accept
activeClass: "isDropDest",
//hoverClass: "isDragging",
//this is used for both drag/drop and item moves
drop: function(event, ui) {
var draggableId = ui.draggable.attr("id");
var droppableId = $(this).attr("id");
//var sender_id = ui.sender.attr('id');
//var receiver_id = $(this).attr('id');
//var item_id = ui.item.attr('id');
//var above_id = ui.item.prev().attr('id');
//var below_id = ui.item.next().attr('id');
//check if this is a drag/drop or a move by looking for the object class
if(!$('#'+draggableId).hasClass('object')) {
$('#'+draggableId).css('top', '0px');
$('#'+draggableId).css('left', '0px');
createObject(draggableId, droppableId);
} else {
//handle the move - do nothing
} //end if
event.stopPropagation();
} //end drop
}); //end droppable
Sorry, not enough coffee today.
Sounds like you may need to use the greedy option
By default, when an element is dropped on nested droppables, each
droppable will receive the element. However, by setting this option to
true, any parent droppables will not receive the element.
$( ".selector" ).droppable({ greedy: true });
Working Example
I have implemented a drag & drop feature using JQuery UI - my current code is provided below:
My JavaScript function receives JSON array from PHP and then uses a loop to create the draggable elements:
<script type="text/javascript">
function init() {
var items = <?php echo $result_j;?>; //items is an one dimensional array
for ( var i=0; i<<?php echo $total_rows_j;?>; i++ ) {
$('<div>' + items[i] + '</div>').data( 'item_name', items[i] ).attr( 'class', 'snk_button' ).appendTo( '#drag' );
}
With the 'items' array I have created several div elements (above code) which I then turn into draggable elements (code below).
$(".snk_button").draggable( {
containment: '#drag_section',//Div #drag_section contains the Div #drag
stack: '#drag div',
cursor: 'move',
revert: true
} )
Below is my droppable code:
$( "#dropp" ).droppable(
drop: handleDrop
});
function handleDrop( event, ui ) {
ui.draggable.draggable( 'option', 'revert', false );
} // End function handleDrop
So far, everything is fine with the draggable items attaching themselves to the droppable div.
Now, I want to tweak this behavior a little:
I want the draggable items to arrange themselves 'automatically' in the droppable div (called '#dropp' in this example), starting from the top left (they will be floating left). Currently this is not happening even though the '#dropp' div has the 'float:left' property set. So, what should I do to have the draggable items arrange themselves when dropped on '#dropp'?
When I take out a draggable item out of the droppable div ('#dropp') I want it return to the div that originally contained the draggable items ('#drag' in this example).
Can you please help implement these 2 behaviors?
After trying this on my own and some R&D for nearly 5-6hrs, I have been able to solve both my problems.
For benefit of others who might be facing the same issues, below is the additional code that is required to implement the behaviors described above:
$( "#dropp" ).droppable({
accept: '#drag div',
drop: function(event, ui)
{
$("div#dropp").append (ui.draggable);
$(ui.draggable).css ({ position:"relative", top:"0px", left:"0px" })
.addClass("moved");
} // End function for handling drop on '#dropp'
}); //End $( "#dropp" ).droppable
This has been added new:
$( "#drag" ).droppable({
accept : ".moved",
drop : function (event, ui)
{
$("div#drag").append (ui.draggable);
$(ui.draggable).css ({ position:"relative", top:"0px", left:"0px" });
} // End function for handling drop on '#drag'
}); // End $( "#drag" ).droppable
That's all is required to implement the behaviors described above. Hope somebody finds the information useful :-)
I have seen only a couple variants on this question asked a couple other places, notably here and here.
Basically, I have a checkers gameboard where each square on the board is a droppable and each gamepiece is a draggable. Each square can only have one piece on it at a time, and I am trying to toggle the enable/disable method depending on whether there's a piece on the square or not.
Here's a link to what I've got so far: http://jsbin.com/ayalaz, and below is the most pertinent code.
function handleDrop(e, ui) {
var tileNumber = $(this).data('tile');
// Make the gamepiece snap into the tile
ui.draggable
.data({ // WHAT IF PIECE IS SET BACK DOWN IN SAME TILE... CHECK FOR IT!
'preRow': ui.draggable.data('curRow'),
'preCol': ui.draggable.data('curCol'),
'curRow': $(this).data('row'),
'curCol': $(this).data('col')
});
$(this).append($(ui.draggable));
ui.draggable
.position({
of: $(this),
my: 'left top',
at: 'left top'
});
$(this).droppable('disable');
//console.log("Gamepiece set down at: (" + $(this).data('row') + "," + $(this).data('col')+ ")");
}
function handleOut(e, ui) {
// HOW TO TOGGLE DROPPABLE??
$(this).droppable('enable');
}
Any advice?
Thanks in advance!
Jeremy
It looks like you are successfully disabling droppable on a tile after the first drop event. Your problem is that you are not initially setting droppable to disabled on the initial set of occupied tiles.
After you've created your game board and pieces, this should accomplish that, assuming my CSS selector accurately reflects your structure:
$('div.gamePiece').parent().droppable("option", "disabled", true);
Note that this is different from the syntax to change droppability in the initial options. From the jQuery UI droppable documentation:
//initialize
$( ".selector" ).droppable({ disabled: true });
//setter
$( ".selector" ).droppable( "option", "disabled", true );
Edit
It appears I was wrong about $(this).droppable('disable'); and $(this).droppable('enable'); jquery-ui does have alias functions for enable and disable.
enable: function() {
return this._setOption( "disabled", false );
},
disable: function() {
return this._setOption( "disabled", true );
},
I have a jquery UI drag and drop for an inventory. It works but i want it to not happen if my inventory already has 20 items in (if it's full).
I'm not that great at javascript/jquery, I can't figure out how to fix my code to do this. I want it to revert back to it's original position if the inventory is full.
Here's the function I'm using to drag/drop
function itemInSpot(drag_item,spot) {
// this is my count. i don't want it to drop an item if it's 20 or more.
var inv_count = parseInt(<? echo count($inv_item) ?>, 10);
var oldSpotItem = $(spot).find('img');
oldSpotItem.appendTo('#inventory').draggable({ revert: 'invalid' });
var item = $('<img />');
drag_item.empty().remove();
item.attr('src',drag_item.attr('src')).attr('title',drag_item.attr('title')).attr('id',drag_item.attr('id')).attr('class',drag_item.attr('class')).appendTo(spot).draggable({ revert: 'invalid' });
}
This is the code that runs the function, set on pageload:
$(document).ready(function() {
$(".weapons,.shield").draggable({ stack: "div", revert: 'invalid'});
$('#inventory').droppable();
$("#weapon_spot").droppable({ accept: '.weapons'})
$('#shield_spot').droppable({ accept: '.shield'});
$('#weapon_spot,#shield_spot,#inventory').bind('drop', function(ev,ui) { itemInSpot(ui.draggable,this); });
});
So how can I add a if inv_count > 19 then revert item back to it's original position in?
Here's a basic jsFiddle example that has six draggable/droppable items, and after the third item is dropped on the target, an alert is triggered and no other draggables are allowed in the droppable area. The elements retain thair draggable property and revert to their original position if a drop is attempted.
jQuery:
$(".ui-widget-content").draggable({
revert: "invalid"
});
$("#droppable").droppable({
drop: function(event, ui) {
$(this).addClass("ui-state-highlight").find("p").html("Dropped!");
$(ui.draggable).addClass('in');
if ($('.in').length == 3) {
$("#droppable").droppable("option", "accept", ".in");
alert('Full!');
}
}
});
I've got a sortable panel (jQuery UI) on my website, but need to limit the amount of elements in each column to a maximum of 12.
I've tried a few things, but can't seem to get it to work. I need to see if 'i' is 12 or greater, and if so, don't update but I can't seem to do it!
Anyone got any advice or can push me the right way?
The jQuery is below!
function updateWidgetData(){
var items=[];
$('.column').each(function(){
var columnId=$(this).attr('id');
$('.dragbox', this).each(function(i){
var collapsed=0;
if($(this).find('.dragbox-content').css('display')=="none")
collapsed=1;
var item={
id: $(this).attr('ID'),
collapsed: collapsed,
order : i,
column: columnId
};
items.push(item);
});
});
var sortorder={ items: items };
//Pass sortorder variable to server using ajax to save state
$.post('includes/updatePanels.php', 'data='+$.toJSON(sortorder), function(response){
if(response=="success")
$("#console").html('<div class="success">Your preferences have been saved</div>').hide().fadeIn(1000);
setTimeout(function(){
$('#console').fadeOut(1000);
}, 2000);
});
}
Sortables
For connected sortables, the solution is to count the elements in each sortable when dragging starts, and disable the ones which have the maximum number of allowed elements. We need to exclude the current sortable, so we can re-order the items within and allow the current element to be dragged.
The problem here is that if we do the above on any of the sortables' events, it's already too late and disabling them won't have any effect. The solution is to do the bind the check to the mousedown event of the items themselves, which will fire before the sortable would get any control. We also need to re-enable all sortables when dragging stops.
Have a look at this example, using <ul> sortables with <li> items, the maximum number of items in each sortable is 3: http://jsfiddle.net/qqqm6/10/
$('.sort').sortable({
revert: 'invalid',
connectWith: '.sort',
stop: function(){
// Enable all sortables
$('.sort').each(function(){
$(this).sortable('enable');
});
}
});
$('.sort li').mousedown(function(){
// Check number of elements already in each sortable
$('.sort').not($(this).parent()).each(function(){
var $this = $(this);
if($this.find('li').length >= 3){
$this.sortable('disable');
} else {
$this.sortable('enable');
}
});
})
Draggables and droppables
The theory is simple, the solution is a bit tricky, there should really be a proper option in jQuery UI to cancel the operation on drop. If there is, but I missed something, please let me know.
Anyways, here's how you check for maximum count in the drop event (maximum of 4 in this example):
$('.drag').draggable({
revert: 'invalid',
stop: function(){
// Make it properly draggable again in case it was cancelled
$(this).draggable('option','revert','invalid');
}
});
$('.drop').droppable({
drop: function(event,ui){
var $this = $(this);
// Check number of elements already in
if($this.find('.drag').length >= 4){
// Cancel drag operation (make it always revert)
ui.draggable.draggable('option','revert',true);
return;
}
// Put dragged item into container
ui.draggable.appendTo($this).css({
top: '0px',
left: '0px'
});
// Do whatever you want with ui.draggable, which is a valid dropped object
}
});
See this fiddle in action: http://jsfiddle.net/qqqm6/