I have a droppable unordered list named <ul class="droppable">. Inside the unordered list I have dynamicly generated list items named <li class="placeholder"></li>, which are also droppable.
When dropping a draggable item between a placeholder, all works fine. But when dropping a draggable item on the <li class="placeholder"></li> itself, the draggable item gets appended to the placeholder and the unordered list.
So I get a double clone of it.
Here's a jsfiddle to have a visual example. I'm aware that it is logical that I get a double clone on my page, but I don't know how to disable it...
Any help is greatly appreciated!
UPDATE: If you drag a draggable item verticaly over a droppable element, they append automatically? How is that possible?
One approach you could try to solve this would be to move all your behaviors to your sortable and use droppable only to make a switch to determine the behavior you need. That way, you can handle everything at one place, which should resolve some of the unwanted effects of having both sortable and droppable on the same elements. Like this:
In your droppable you set the switch on over and out, and set the objects you need.
$("li.placeholder").droppable({
accept: "li.to-drag",
hoverClass: "correct",
activeClass: "active",
revert: false,
tolerance: "pointer",
over: function (e, ui) {
curDrag = ui.draggable;
curTarget = e.target;
curThis = $(this);
overSortable = true;
},
out: function (e, ui) {
overSortable = false;
},
drop: function (event, ui) {
}
});
Then, in beforeStop event of sortable, you check if the variable overSortable is true or not and set the behaviors there. All that refers to ui.draggable, this, and event.target will need to be replaced by the objects you set in droppable. An event better way would be to make a function handling all these behaviors and pass these as arguments.
beforeStop: function (e, ui) {
if (overSortable) {
curDrag.addClass('placeholder');
var dragging = curDrag.find("img").remove();
curThis.append(dragging).addClass("dropped");
curThis.droppable('disable');
var day = curDrag.attr('data-id');
var index = $(curTarget).index();
//...
} else {
ui.item.addClass('placeholder')
}
There are still adjusments to make, it's not completely clear what exactly should happen and when, but this can make it easier to work instead of trying to manage multiple events being fired when you drop an element, you only manage one.
http://jsfiddle.net/ts290vth/4/
Managed to get it working for you:
function dropping () {
$("li.placeholder").droppable({
accept: "li.to-drag",
hoverClass: "correct",
activeClass: "active",
revert: false,
tolerance: "pointer",
drop: function (event, ui) {
var dragging = ui.draggable.find("img");
$(this).append(dragging).addClass("dropped");
$(this).droppable('disable');
var day = $(ui.draggable).attr('data-id');
var index = $(event.target).index();
$(this).attr("data-id", day);
$(this).attr("date-order", index);
$(this).addClass("drop-"+ index);
$(this).attr("data-content", "");
NOTICE: the var dragging = ui.draggable.find("img"); this line was making you duplicated copies at drag and drop so you just had to remove the clone();.
it created clones of your dragged items at dest.
Now Notice this:
$("#dropzone").droppable({
accept: "li.to-drag",
revert: false,
tolerance: "pointer",
drop: function (event, ui) {
$(this).append(dragging);
//$("li.to-drag").addClass("placeholder");
$(this).droppable('disable');
}
});
}
Something with the placeholder class is causing you troubles.
Hope this helps.
Related
I'm trying to drag "templates" (initially as clones) from a "store" into droppable slots. Thereafter I want to be able to drop the dragged item into whatever slot I wish. Draggables are set as follows:
$( ".template" ).draggable({
helper: "clone",
}
);
$( ".item" ).draggable();
I got round the issue of the thing re-cloning by replacing the "template" class with an "item" class on first drop and within the drop function switching from a clone to a straight element as follows:
$( ".template-slot" ).droppable({
accept: ".template, .item",
drop: function( event, ui ) {
if(ui.draggable.hasClass("template")) {
$(this).append(ui.draggable.clone())
// add item class
$(".template-slot .template").addClass("item");
// remove template class
$(".item").removeClass("ui-draggable template");
// expand to fit the slot
$(".item").addClass("expand-to-slot");
// make it draggable again
$(".item").draggable();
}
if(ui.draggable.hasClass("item")) {
$(this).append(ui.draggable);
}
}
});
The first drag and drop works okay. the problem arises on the second drag and drop. The element drags okay but when dropped it gets placed twice as far in whatever direction I drag it. So, for example, if I've dragged it 50px to the right, it drops 100px to the right. the same with up and down etc.
I suspect it's something to do with the offset being cumulative but haven't worked out why it's doing this or how to fix it.
I've created a fiddle here: https://jsfiddle.net/stefem1969/a86jmnxu/10/ to show the problem.
Hope someone can help.
Working Example: https://jsfiddle.net/Twisty/fu83zq2y/11/
JavaScript
$(function() {
function makeDrag(obj, opt) {
if (obj.hasClass("ui-draggable")) {
obj.removeClass("ui-draggable");
obj.attr("style", "");
}
if (opt === undefined) {
opt = {};
}
obj.draggable(opt);
}
makeDrag($(".template, .item"), {
helper: "clone",
});
$(".template-slot").droppable({
accept: ".template, .item",
drop: function(event, ui) {
if (ui.draggable.hasClass("template")) {
console.log("it has the template class!");
var newItem = ui.draggable.clone();
newItem.toggleClass("template item");
newItem.addClass("expand-to-slot");
newItem.appendTo($(this));
makeDrag(newItem);
}
if (ui.draggable.hasClass("item")) {
console.log("it has the item class!")
var droppableOffset = $(this).offset();
console.log("droppableOffset: ", droppableOffset);
ui.draggable.attr("style", "").appendTo($(this));
}
}
});
$(".template-store, .thagomizer").droppable({
accept: ".item",
drop: function(event, ui) {
ui.draggable.remove();
}
});
});
Part of draggable is to set a top and left when moving it around. Even if you append the item to another element, it will still have those. Clearing that can help accomplish what you're looking for.
The makeDrag() is just helpful to perform the same operations a lot.
Hope this helps.
So what i'm trying to do is to place an item( the diamond shaped item ) in the droppable and that item creates 2 sub-droppables in wich you place items, but the thing is i can't seem to get the "greedy" function to work with the generated droppables. Currently i'm only testing it on the second item - left side when generated.
my My jsFiddle .
This is the main dropzone.
$(".objects").droppable({
accept: "#block",
drop: function (ev, ui) {
$(".test").append('Dropped!');
}});
This is the sub-dropzone. On drop there should appear Dropped123! in the bottom code paragraph.
$(".true").droppable({
greedy:true,
accept: "#block",
drop : function (ev, ui) {
$(".test").append('Dropped123!');
}
});
Your problem is that you are trying to bind droppable before you actually have the elements, I have changed your fiddle so now you bind the event to the actual element:
http://jsfiddle.net/L22d4x2x/7/
var divTrue = $('<div class="true n_block'+ cloneCount1 +'"></div>');
$(".n_block"+ cloneCount1 ).append(divTrue);
divTrue.droppable({
greedy:true,
accept: "#block",
drop : function (ev, ui) {debugger;
$(".test").append('Dropped123!');
}
});
I googled and found several answers but they was all about click or mousemove events which are not suitable for my question.
Basically I allow users to drag an item from a list and drop it on a folder in another list and I want to highlight element (in the folder list) whenever an item is dragging over it. Listening to mouseenter and mouseleave events on the folder list won't work. I tried with document.elementFromPoint in the dragging event (jQuery UI's Draggable drag) but unfortunately it returns the helper element instead of the element in the folder list. I think it's correct behavior since document.elementFromPoint returns the top most element under mouse cursor. But it doesn't solve my problem :(.
$("#filelist li").draggable({
helper: "clone",
drag: function (event, ui) {
console.log(event.pageX, event.pageY);
var element = document.elementFromPoint(event.pageX, event.pageY);
// element is helper element, instead of actual element under cursor which I want.
}
});
$("#folderlist").droppable({
drop: function (event, ui) {
}
});
// These mouse events won't be triggered while dragging an item.
$("#folderlist").on({
"mouseenter": function (event) {
this.style.backgroundColor = "#1c70cf";
},
"mouseleave": function (event) {
this.style.backgroundColor = "";
}
}, "li");
Apparently, the droppable has an hover function. http://jqueryui.com/droppable/#visual-feedback
$("#folderlist").droppable({
hoverClass: "ui-state-hover",
drop: function (event, ui) {
}
});
Then add this to your css :
.ui-state-hover
{
background-color: #1c70cf;
}
I have three sortable list boxes, one grey and two yellow. I can drag and clone child sortable li's into the bottom yellow lists no problem.
The problem is that once the child clone li's from the grey list box are placed into the yellow list boxes, you can no longer drag/shift them within the containing yellow list box or to the adjacent yellow list box. They just clone continuously when you attempt to drag them elsewhere.
I would like to drag and clone sortables from the grey list box into the yellow boxes and have the cloned child li's be able to drag and move within the yellow lists boxes without cloning.
How can I prevent the child li's from cloning. Any help would be much appreciated. Thanks.
http://jsfiddle.net/equiroga/96hJj/
$(function() {
$(".sortable").sortable(
{
helper : "clone",
connectWith : ".sortable",
start : function(event,ui)
{
$(ui.item).show();
clone = $(ui.item).clone();
before = $(ui.item).prev();
position = $(ui.item).index();
},
beforeStop : function(event, ui)
{
if($(ui.item).closest('ul#sortable1').length>0)
$(this).sortable('cancel');
},
stop : function(event, ui)
{
if (position == 0) $("#sortable1").prepend(clone);
else before.after(clone);
}
});
$(".sortable").sortable();
});
You can set a particular behavior for the first list and a different for the others, the others can't interact with the first using a coonectWith selector with :not selector.
Code:
$(function () {
$("#sortable1").sortable({
helper: "clone",
connectWith: ".sortable",
start: function (event, ui) {
$(ui.item).show();
clone = $(ui.item).clone();
before = $(ui.item).prev();
position = $(ui.item).index();
},
beforeStop: function (event, ui) {
if ($(ui.item).closest('ul#sortable1').length > 0) $(this).sortable('cancel');
},
stop: function (event, ui) {
if (position == 0) $("#sortable1").prepend(clone);
else before.after(clone);
}
});
$(".sortable").sortable({connectWith: ".sortable:not('#sortable1')"});
});
Demo: http://jsfiddle.net/IrvinDominin/923VG/
I have a list of draggable objects and a droppable target. The view housing the droppable target gets created and rendered when dragging starts. I've attached some images highlighting the desired action to the bottom of the post.
The issue is that jQuery UI appears to have a bug. This post: Droppable items not displaying hoverClass if they are shown during drag operation seems to corroborate that belief.
I have this code which enables draggable-ness:
this.$el.find('.videoSearchResultItem ').draggable({
helper: function() {
var helper = $('<span>', {
text: VideoSearchResultItems.selected().length
});
return helper;
},
appendTo: 'body',
containment: 'DOM',
zIndex: 1500,
cursorAt: {
right: 20,
bottom: 30
},
start: function (event, ui) {
var draggedVideoId = $(this).data('videoid');
var draggedVideo = VideoSearchResultItems.get(draggedVideoId);
draggedVideo.set('selected', true);
$(ui.helper).addClass("ui-draggable-helper");
}
});
My program has an event listener for a video search result becoming selected. When one becomes selected, the 'AddItems' view renders itself and transitions in.
this.listenTo(VideoSearchResultItems, 'change:selected', function (changedItem, selected) {
if (selected && this.addItemsView === null) {
this.addItemsView = new AddItemsView();
this.$el.append(this.addItemsView.render().el);
this.addItemsView.show();
}
});
AddItemsView initializes droppable during render:
this.$el.find('i.droppable').droppable({
hoverClass: 'icon-drop-hover',
tolerance: 'pointer'
});
Unfortunately, if my draggable is already dragging when the view is rendered -- hoverClass fails as well as the 'over' event.'
I'm wondering if there's any workaround for this? I don't see one.
The solution to this was to set the draggable element's "refreshPositions" option to true. This causes it to inform the droppable even if the droppable is created late.