JQuery Draggable - Odd Behavior - javascript

I have a draggable element that I am creating a clone of and dragging to a drop zone. I want the draggable element to be re-draggable once it is set down in the drop zone correctly.
The odd behavior comes into play when I encapsulate the draggable div within another div. When it is encapsulated, it will not set the clone element to draggable, so I cannot re-drag the element. However, if in the jFiddle, you remove the divs from surrounding the draggable div, the thing works fine.
Working:
<div id="draggable"></div>
Not Working:
<div><div id="draggable"></div></div>
I need to know why the encapsulation is fooling around with this. It seems like it would be difficult to build a meaningful thing with a problem like this because I want to have a sidebar containing multiple draggables similar to these. Since building a sidebar requires encapsulating all these draggable elements within another div, you can see the conundrum I've happened upon.
The jFiddle links below contain the Jquery, and such.
Here is the jFiddle that doesn't work rightly: here.
And, here is the jFiddle that works correctly: here.
The only difference in the one that doesn't work: the dome class div is encapsulated by another div.

You need to remove the draggable on blah and add the draggable to the clone that is appended in the stop block.
Try this:
$(function() {
var i=1;
var indexP;
var blah
$(".dome").draggable({
revert: 'invalid',
helper: 'clone',
start: function(event, ui) {
var newId = i;
$(ui.helper).attr("id",newId);
indexP = $(ui.helper).attr('id');
blah = "#" + indexP;
},
stop: function(event, ui) {
$(ui.helper).append("<br><span>"+blah+"</span>");
$(ui.helper).clone().appendTo('#cont').draggable();
i++;
},
});
$("#cont").droppable({
});
});
function updateStatus (x,y,i) {
var xPos = "#x" + i;
var yPos = "#y" + i;
$(xPos).text(x);
$(yPos).text(y);
}

Related

Change the dragged object when draggable begins

I am trying to create some thing like a UI designer. So I have a 'toolbox' and a 'canvas'. When I mark the tool box items as draggable, I am able to drag them. But what I need is to drag a copy, so that I can drag multiple instances of a tool item to the canvas.
$('.tool-box-item').draggable({
helper : 'clone',
drag : function (event, ui){
// jQuery does not allow object modification here
},
});
This does not work as the cloning is applied only while dragging and as soon as the drag is complete, the original element moves. I tried overriding the drag property, but I am unable to modify the dragged element. Same was the case with start.
Note : I can not use the stop event as I want to create the copy when the drag starts and not after it. I was also able to create a copy by defining the canvas as droppable and making a copy there, But then again I want to create a copy when the drag starts.
I think I will need to create a custom drag function but was hoping if jQuery has any other alternative way.
Here is a jsfiddle, but I want to clone the element at the start and not after the drag.
EDIT : The destination is a 3rd party control. It has its own implementation for drop event (stacking and aligning). In case I clone it at the end I will have to modify their implementation.
To keep "dragend" event, try to use original element for dragging, and clone it for place to your "toolbox".
var graggableConfig = {
helper:"clone",
stop: function(event, ui){
var clon = $(this).clone();
clon.attr("style","")
.appendTo(".src")
.draggable(graggableConfig);
$(this).detach()
.attr("style","")
.appendTo(".dst")
.draggable( "destroy" );
}
};
$(".item").draggable(graggableConfig);
codepen here
You can use jquery's clone (https://api.jquery.com/clone/) method to clone your draggable element once it is dropped. Would something like this meet your needs?
$( function() {
makeDraggable($( "#draggable" ));
});
function makeDraggable(element) {
$(element).attr('style', 'position:absolute').draggable({
start: function() {
makeDraggable($('#draggable').clone().attr('style', '').appendTo('body'));
}
});
}
Its a little rough but here is the jsbin: https://jsbin.com/tasodixoka/edit?html,output
Edit: I updated your fiddle: https://jsfiddle.net/z9rrL6po/6/

How to avoid hover/mouseenter being called again when creating child elements dynamically

I'm dynamically creating a box inside an element, say A, whenever the user hovers over A. The box, B, is then moved around with the mouse. B should only appear when the user is hovering over A (i.e. it is removed on mouseleave).
Unfortunately, if I dynamically create elements inside B, when the mouse moves over them, the hover event is called again (creating a new B). This issue seems to happen when I dynamically create B's children on the mouse move. At first I thought it was to do with bubbling, and needing to delegate, but now I feel it has to do with the fact I'm emptying the box and filling it again (thereby causing the hover event to fire again)?
This example illustrates what I'm having a problem with:
https://jsfiddle.net/shzy6gtx/
function positionBox(element, position) {
element.css({
top: position - element.parent().offset().top - 10,
});
element.empty();
jQuery('<span />').appendTo(element).text(position);
}
$(document).bind('mousemove', function(e) {
if ($('#theBox').length <= 0)
return;
positionBox($('#theBox'), e.pageY);
});
$('.hover').hover(function(e) {
var innerBox = jQuery('<div />', {
id: 'theBox',
class: 'inner',
}).appendTo(this);
positionBox(innerBox, e.pageY);
}, function(e) {
$('#theBox').remove();
});
This is how it should work (without the dynamically created span tags):
https://jsfiddle.net/dffyt6gx/
If this is something I can't solve, how else can this be accomplished?
For me the problem in fact looks like both:
an event-bubbling problem.
a problem with the repeated rapid creation of the position-span
My theory is that when the label is destroyed with .empty() while the mouse is hovering the position label, and it is not added back again fast enough, this will be considered as another mouse-enter event.
Now 1. can be solved by simply adding
if (e.delegateTarget != e.target)
return;
to the hover event handler. You can observe notice that the problem occurs way less often.
For 2.
One simple solution would be to not create the label again every time the mouse (and B) are moved.
have a look at https://jsfiddle.net/IARI/w8y1y3vt/
If for some reason you want to or have to create the element(s) inside B every time this wont help. However if it is possible not to recreate them I would advise you to do so, if only for performance reasons.
If simply checking, whether B exists is an option for you, that would solve it as well while allowing you to recreate the position-label - https://jsfiddle.net/IARI/shzy6gtx/6/
Don't know if this can help you but you are assigning a #id to each div and trying to work with those elements an #id must be unique in the DOM.
$(document).bind('mousemove', function(e) {
if ($('.inner').length <= 0)
return;
positionBox($('.inner'), e.pageY);
});
$('.hover').hover(function(e) {
var innerBox = jQuery('<div />', {
id: 'theBox',
class: 'inner',
}).appendTo(this).click(function(e) {
});
positionBox(innerBox, e.pageY);
}, function(e) {
$('.inner').remove();
});
Maybe this can give you a clue
Added a fiddle
You can move the handler out.
**$('body').on('click','#theBox', function(e){
alert('event handler'); });**
$('.hover').hover(function(e) {
var innerBox = jQuery('<div />', {
id: 'theBox',
class: 'inner',
}).appendTo(this);
jQuery('<span />').appendTo(innerBox).text('number');
positionBox(innerBox, e.pageY);
}, function(e) {
$('#theBox').remove();
});

jQuery object not draggable when recreated

Please visit http://classrecon.com/invest/mockup.html for the example of my problem. To recreate the problem:
Drag PULM into the "Has these targets..." field and drop.
Delete the tag by hitting the X to the right of the tag.
PROBLEM: Notice that when you try to drag <delete element's text> the element won't drag.
How can I make the new tag draggable? And how can I transfer the deleted tag's text to the new tag?
JS:
$(function(){
$(".drag-key").draggable();
$(".tag-collection").droppable({
over: function(event, ui){
$(this).css("background-color","rgba(0,191,255,.3)");
},
out: function(event, ui){
$(this).css("background-color","white");
},
drop: function(event, ui){
$("<div class='key'></div>").text( ui.draggable.text() ).appendTo( this ).append(" <span class='remove'>✘</span>");
ui.draggable.remove();
}
});
// I THINK THE PROBLEM IS HERE
$(document).on('click', 'span.remove', function() {
$(".key-rep").append("<div class=\"drag-key key\"><removed element's text></div>");
$(this).closest('.key').hide();
});
});
you need to run the line $(".drag-key").draggable(); again at the end of $(document).on('click', 'span.remove', function() {
It should look like this
$(document).on('click', 'span.remove', function() {
$(".key-rep").append("<div class=\"drag-key key\"><removed element's text></div>");
$(this).closest('.key').hide();
$(".drag-key").draggable();
});
Here is a JSFiddle with the suggested fix
JSFiddle
When you .append() the markup for a new drag-key, it is just that.. a brand new element. It was not present at the time you created the selected $(".drag-key"), and made all elements matching that selector draggable. It doesn't contain the events or class associated with JQuery draggables. If you want to make your new drag-key draggable, you'll have to .draggable() the newly created element just like you did the original element(s).
You should use delegate() method to make divs draggable when appends to key-rep.

JQuery UI: Cancel Sortable upon Droppable Drop

I am using JQuery 1.5.1 and JQuery UI 1.8.11.
I have added sortable for a number of items - the task here is to allow drag to sort, this all works fine.
But I also want to incorporate droppable, so that the item can be dropped onto a "copy me" area - the task there will be to duplicate the item (I will work that bit out later)
Problem is the droppable target is at the bottom of the sortable list (I do not want to move this) and once the drop occurs the sortable item moves to the bottom of the list.
What I want to do is cancel this sort when the drop event fires.
You can see my problem in action here (just drag "Item 1" onto the "Drop to Copy Item" area and you will see the sort does not get cancelled)
As you can see I have tried the following in the droppable "drop" event (suggested from JQuery UI Docs) but it does not seem to work...
$(this).sortable('cancel');
I am also open to any other recommendations on how to achieve this "drop to copy" effect I am looking for.
Thanks
OK, so I have worked out a solution which does the job.
the cancel code does work if you have it in the "stop" event of the sortable function. However, it will only apply once the "revert" has completed. The problem is that I was trying to copy/revert the element from the droppable "drop" event and this was too early.
The solution is to wait for the "stop" event to complete, and to achieve this I had to create a "awaiting copy" flag, to be checked in the "stop" event.
Here is an example
It still doesn't feel right (UX-wise) but it works correct, and you could always set revert to false on the sortable function to get a slightly better feel.
The code from the example is as follows...
var itemCount = 3;
var awaitingCopy = false;
$(init);
function init() {
$("#Items").sortable({
revert: true,
placeholder: "ItemPlaceHolder",
opacity: 0.6,
start: StartDrag,
stop: StopDrag
});
$("#CopyItem").droppable({
hoverClass: "CopyItemActive",
drop: function(event, ui) {
awaitingCopy = true;
}
});
$("#NewItem").click(function(e) {
e.preventDefault();
itemCount++;
var element = $("<div class='Item'>Item " + itemCount + "</div>");
$("#Items").append(element);
element.hide().slideDown(500);
});
}
function CopyItem(element) {
awaitingCopy = false;
var clone = element.clone();
$("#Items").append(clone);
clone.hide().slideDown(500);
}
function StartDrag() {
$("#NewItem").hide();
$("#CopyItem").show();
}
function StopDrag(event, ui) {
if (awaitingCopy) {
$(this).sortable('cancel');
CopyItem($(ui.item));
}
$("#NewItem").show();
$("#CopyItem").hide();
}
Anyway, hopefully this will help others who want the same kind of effect... no stealing my design though ;)

jQuery draggable problem with 'scroll' on object inside overflow:hidden container when using appendTo: 'body'

I have a draggable object, with that can be accepted in several droppables.. I have put all the droppables in a container, and simply want to be able to detect when the draggable is hovering over the container of droppables...
At first, I tried making use of the 'over' and 'out' callbacks for droppables, but it was not working because hovering from one droppable to another (inside the same container) was causing it to think the mouse had left the container...
So my next approach was to in the drag start callback, do an event listener for mouseenter and mouseleave on the container-- and then stop listening on the drag stop callback...
However, this results in total crazy behavior... If you look at my example page:
http://collinatorstudios.com/www/jquery_draggable_test.html
When dragging the box to the red dropzone, you should see "enter" when the mouseenter event fires, and "leave" when mouseleave happens.. However, just dragging the box over the inside of the container causes "leave" to appear a zillion times..... I cannot figure out why this is happening, nor what solution there is to my problem so I can do what I need to. I've been working on this for almost 4 hours now and am losing my mind over what seems like it should be so simple to achieve.
Any help would be greatly appreciated... Thanks.
Try adding a droppable for the container:
$('#drop_zone_container').droppable({
over: function(){ feedback.text('enter')},
out: function(){feedback.text('leave')}
});
You only need to bind to the events once! There is no need to bind and unbind them each time... I separated them out in the code below to make it more clear about binding once.
And as ZDYN said (+1 to him), you need to include a droppable code, but instead of using the container, use the zones inside... here is a demo and the full code below.
var feedback = $('#feedback');
$('.item').draggable({
revert: true,
zIndex: 999,
cursor: 'move'
});
$('.drop_zone').droppable({
drop: function(event, ui) {
ui.draggable.appendTo($(this));
}
}).bind('dropover dropout', function(e) {
var id = this.id;
feedback.text(e.type === 'dropover' ? 'Over: ' + id : 'Out: ' + id);
});

Categories

Resources