Currently I'm having a small problem with the demo at http://jsfiddle.net/nivea75ml/yCnh5/.
Whenever I drag a pink box from the list to the grey area and later move it back, it covers another one in the same list.
How can this behaviour be avoided?
Droppable and sortable
$('#draggableList').sortable({
receive: function(event, ui) {
var item = $('.ui-draggable-dragging');
item.removeAttr("style");
item.removeAttr('class');
item.addClass('draggable');
}
});
var $tab_items = $("#droppable").droppable({
//accept: ".draggable",
hoverClass: "ui-state-hover",
drop: function(event, ui) {
var item = $(this);
var olditem = $(".draggable.ui-sortable-helper").clone();
if (olditem[0] != null) {
olditem.removeAttr('class');
olditem.addClass('dragged');
olditem.css({
'position': 'absollute',
'top': ui.offset.top,
'left': ui.offset.left
});
olditem.draggable({
connectToSortable: "#draggableList",
helper: "original",
revert: 'invalid'
});
ui.draggable.remove();
$('#droppable').append(olditem).show("slow");
}
},
out: function(event, ui) {}
});
http://jsfiddle.net/yCnh5/25/
Related
There are two lists of items need to be mapped into a table. I've create the table and draggable list item followed by reference-style link to Accessing table cell data within list items with Javascript.
The current situation
I have two lists, and need to be filled into two columns(with different ids); ideally, the the credit card list item can only be put into credit card column, vice versa for api list and api field.
The current issue
When I dragged items from api list to api field, it displayed double text.
Two list items can drag into different fields. How can I make the list items limited into matched table column?
Here is the JsFiddle along with some sample code:
$("#ccField li").draggable({
appendTo: "body",
helper: "clone",
cursor: "move",
revert: "invalid"
});
$("#apiField li").draggable({
appendTo: "body",
helper: "clone",
cursor: "move",
revert: "invalid"
});
ccDroppable($("#creditCardApiTable table td"));
apiDroppable($("#creditCardApiTable table td"));
function ccDroppable($elements) {
$elements.droppable({
activeClass: "ui-state-default",
hoverClass: "ui-drop-hover",
accept: ":not(.ui-sortable-helper)",
over: function (event, ui) {
var $this = $(this);
},
drop: function (event, ui) {
var $this = $(this);
$("<span></span>").text(ui.draggable.text()).appendTo(this);
$("#ccList").find(":contains('" + ui.draggable.text() + "')")[0].remove();
}
});
}
function apiDroppable($elements) {
$elements.droppable({
activeClass: "ui-state-default",
hoverClass: "ui-drop-hover",
accept: ":not(.ui-sortable-helper)",
over: function (event, ui) {
var $this = $(this);
},
drop: function (event, ui) {
var $this = $(this);
$("<span></span>").text(ui.draggable.text()).appendTo(this);
$("#apiList").find(":contains('" + ui.draggable.text() + "')")[0].remove();
}
});
}
Is this what you are looking for?
http://jsfiddle.net/ryaL3xpk/3/
$("#ccField li").draggable({
appendTo: "body",
helper: "clone",
cursor: "move",
revert: "invalid"
});
$("#apiField li").draggable({
appendTo: "body",
helper: "clone",
cursor: "move",
revert: "invalid"
});
function droppableField($element, $accept) {
$element.droppable({
activeClass: "ui-state-default",
hoverClass: "ui-drop-hover",
accept: $accept,
over: function (event, ui) {
var $this = $(this);
},
greedy:true,
tolerance:'touch',
drop: function (event, ui) {
var $this = $(this);
$this.text(ui.draggable.text()).appendTo(this);
}
});
}
droppableField($('#creditCardApiTable table td .ccDropField'), '#ccField li');
droppableField($('#creditCardApiTable table td .apiDropField'), '#apiList li');
So basically, you allow each span to be droppable, and each accepts different draggable field.
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
Demo: http://jsfiddle.net/py3DE/
$(".source .item").draggable({ revert: "invalid", appendTo: 'body', helper: 'clone',
start: function(ev, ui){ ui.helper.width($(this).width()); } // ensure helper width
});
$(".target .empty").droppable({ tolerance: 'pointer', hoverClass: 'highlight',
drop: function(ev, ui){
var item = ui.draggable;
if (!ui.draggable.closest('.empty').length) item = item.clone().draggable();// if item was dragged from the source list - clone it
this.innerHTML = ''; // clean the placeholder
item.css({ top: 0, left: 0 }).appendTo(this); // append item to placeholder
}
});
$(".target").on('click', '.closer', function(){
var item = $(this).closest('.item');
item.fadeTo(200, 0, function(){ item.remove(); })
});
My goal here is when an item is taken from .source and dropped on to .target, I want to disable the draggable that was dropped so that I can only have a single instance of an item from .source end up in .target. Conversely, I am also trying to re-enable the item once it is removed from .target.
Given that your creating a clone of the original you need to track this and be able to tie back to the original when you close the clone.
var mapOrig = [];
$(".source .item:not(.added)").draggable({ revert: "invalid", appendTo: 'body', helper: 'clone',
start: function(ev, ui){ ui.helper.width($(this).width()); } // ensure helper width
});
$(".target .empty").droppable({ tolerance: 'pointer', hoverClass: 'highlight',
drop: function(ev, ui){
var item = ui.draggable;
if (!ui.draggable.closest('.empty').length) {
var orig = item;
item = item.clone().draggable();// if item was dragged from the source list - clone it
orig.draggable('disable');
mapOrig.push({item: item, orig: orig});
}
this.innerHTML = ''; // clean the placeholder
item.css({ top: 0, left: 0 }).appendTo(this); // append item to placeholder
}
});
$(".target").on('click', '.closer', function(){
var item = $(this).closest('.item');
for(var i = 0; i < mapOrig.length; ++i){
if(item.is(mapOrig[i].item)){
mapOrig[i].orig.draggable('enable');
mapOrig.splice(i, 1);
}
}
item.fadeTo(200, 0, function(){ item.remove(); })
});
I've created an updated fiddle at http://jsfiddle.net/xmltechgeek/FCj2a/ that show a way to do this using a tracking array for your old item when you create the clone. You can just use the enable/disable functionality from jquery for the actual task of enabling or disabling.
use this code inside droppable -
deactivate: function( event, ui ) {
var item = ui.draggable;
item.draggable('disable');
}
Demo Fiddle
Right now I have a column of elements and I have it to the point where where I drag, it clones but when I drop, it removes the original as well.
$( ".column" ).sortable({
helper: 'clone',
connectWith: ".column",
connectWith: ".grid",
start: function(e, ui){
ui.placeholder.height(ui.item.height());
$(".column" ).find('.portlet:hidden').show()
console.log('started')
},
stop: function(event, ui) {
$(ui.helper).clone(true).removeClass('box ui-draggable ui-draggable-dragging').addClass('box-clone').appendTo('body');
}
});
How can I keep the original where its at (without re-appending it to the column) and have the clone move to the desired location?
Use $(this).sortable('cancel') inside the stop event handler to revert the item back to it's original list/position. http://api.jqueryui.com/sortable/#method-cancel
$( ".column" ).sortable({
helper: 'clone',
connectWith: ".column",
connectWith: ".grid",
start: function(e, ui){
ui.placeholder.height(ui.item.height());
$(".column" ).find('.portlet:hidden').show()
console.log('started')
},
stop: function(event, ui) {
$(ui.helper).clone(true).removeClass('box ui-draggable ui-draggable-dragging').addClass('box-clone').appendTo('body');
$(this).sortable('cancel');
}
});
UPDATE:
To append the element to the second list in the location the item was dropping, do something like the following:
stop: function(event, ui) {
var toListID = ui.item.parent().attr('id');
var idx = $('#' + toListID).children().index($(ui.item[0]));
if(idx== -1)return;
var elm = $(ui.item[0]).clone(true).removeClass('box ui-draggable ui-draggable-dragging').addClass('box-clone');
$('#' + toListID).children(':eq('+idx+')').after(elm);
$(this).sortable('cancel');
}
See fiddle for full demo
If anyone using new version just use:
revert: true
More details here: jQuery Sortable - Keep it in original list
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