Change the dragged object when draggable begins - javascript

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/

Related

jQuery UI replacement for "distance" and "delay" options

According to the jQuery UI API Documentation, the "Distance" and "Delay" options are deprecated as of version 1.12. Specifically:
(#10615) Interactions should be instantaneous. These settings are typically used to prevent accidental drags, but a proper fix for that is to improve the user experience, e.g., using handles to avoid accidental drags.
I am using jQuery UI to develop an RPG map builder. Users can drag tiles from the selection area to the grid to place them, or they can click a tile to set it as the "active" tile, then click on tiles in the grid to convert them to a copy of the "active" tile. The issue I run into is that a click-and-very slight drag on a set tile will cause the tile to be removed. I feel using a handle to drag tiles that are already on the map would detract from the user experience by causing them to have to set their pointer to an even smaller area than the tile.
So my question is: What can I use in place of these functions? Would it be best to stay on an old version of jQuery UI? Would it be better to write code to mimic this functionality? Should I use a handle for items already on the grid?
I think I can do a check for if (the dragged element (ui.draggable) is the same as the drop target (event.target), but I'm having trouble coming up with the logic.
My code is located at https://codepen.io/Qumez/pen/OzvbdV. The relevant functions are setDraggableTiles() and setDroppableTiles(), below:
function setDroppableTiles() {
$("#grid .tile").droppable({
accept: ".tile",
drop: function(event, ui) {
drop(event,ui);
}
});
}
function setDraggableTiles() {
$(".tile").not("#grid .placeholder").draggable({
revert: false,
helper: "clone",
stop: function(event, ui) {
var $ele = $(event.target);
console.log($ele);
console.log($(ui.draggable));
if ($ele.hasClass("tile-set")) {
$ele
.removeClass()
.addClass("placeholder tile");
}
}
});
$("#grid .tile").not(".placeholder").addClass("tile-set");
}
Thanks in advance!

How to use delegate for UI draggable?

I have to add draggable and droppable for those new elements inserted on the page, but since they are not yet inherited the draggable and droppable like those that are done during the page loaded, I have to manually add draggable and droppable for those newly created elements.
For click events, I could simply do this
$('body').on({
click:function(){
//codes here
}
},'#element');
but this doesn't seem to work when I deal with draggable and droppable
I have my draggable set up like this
$('.photo-segment').draggable({
containment:'#layout-draggable',
axis:'y',
scroll:false,
revert:"invalid",
drag:function(event,ui){
$(this).css({'z-index':9999, 'opacity':'0.8'});
},
stop:function(event,ui){
$(this).css({'z-index':'', 'opacity':'1'});
}
});
and I droppable set up like this
$('.photo-segment-container').droppable({
accept:'.photo-segment',
tolerance:'intersect',
over:function(event, ui){
//codes here
},
drop:function(event, ui){
//codes here
},
deactivate:function(event,ui){
return false;
}
});
I could have manually run this whole bunch of codes above right after I created those elements, I have done something like this
$('.photo-segment').draggable();
$('.photo-segment-container').droppable();
but in this case, I can't retrieve all those setups. Do I have to run my initial set up again?
Yes, you will need to initialize draggable/droppable again for the newly added elements.
You could save your settings in a separate objects to not repeat the code.
var dragSettings = {...};
...
$('.photo-segment').draggable(dragSettings);

Is there an event called while a jQuery UI draggable element is being reverted to its original position?

I have a draggable element using jQuery UI, and have a function attached the drag event that gets continuously called with the element's position while the user is dragging it.
I also have revert: true set on this element, so when the user stops dragging the element springs back to its original position. Is there a way I can attach a listener to perform the same functionality as when it's being manually moved?
I can't see anything specifically related to the revert property in the docs, so if that's not possible is there a more general event called while an element is moving?
Thanks!
It appears there's nothing in the API for this, so I've had to hack it using setInterval.
var revertInterval;
var revertEvent = function(el) {
revertInterval = setInterval(function() {
// Do things
// e.g. console.log(el.position().top);
}, 5);
}
$('#draggable').draggable({
revert: function() {
revertEvent($(this));
return true;
},
stop: function() {
clearInterval(revertInterval);
}
});
the revert is accept function as follow
revert: function(param){}
DEMO

How to dynamically add an ondragstart event to a dynamically created div

There are a couple of questions that seem to ask this question, but no one accepted answers and nothing has worked for me.
I have a 'group' button that when it's clicked, will dynamically create a 'group' div (I then append some pre-selected 'child' divs within it)
However I need the new 'group' div to be draggable.
I can set the draggable attribute dynamically, no problem.
But being draggable is not much good without the ondragstart() event, and no matter what I've tried, I can't get this assigned.
I am using jQuery which may have a bearing.
The latest iteration of my code is (this appears in an init() function that is called from body.onload):
var group=$(document.createElement('div'));
group.attr({id: 'group'+grpcount});
group.attr({draggable: "true"});
group.addClass('group');
group.html("<span class='group'>Group"+grpcount+"</span>");
$('#boundary').append(group);
document.getElementById('group'+grpcount).addEventListener("startdrag",drag);
But I have also tried various combinations of jQuery .bind:
group.bind("dragstart", drag(ev));
group.bind("dragstart", function(ev){drag(ev);});
All to no avail.
I have a drag function already defined (and I've tried putting it before and after the code above):
function drag(ev) {
ev.dataTransfer.setData("Text",ev.target.id+":"+ev.pageX+":"+ev.pageY);
}
I hope there is something glaringly obvious that I just can't see.
Can somebody solve this?
You'll be better to take a look at Jquery UI draggable here
and if you dont know yet, you can call multiple jquery finctions in a chain, so your code looks more readable like below:
var group=$('div').attr('id', 'group'+grpcount)
.addClass('group')
.html("<span class='group'>Group"+grpcount+"</span>");
$('#boundary').append(group);
and instead of
document.getElementById('group'+grpcount).addEventListener("startdrag",drag);
use this
group.draggable({
start:function(event, ui){
//this is where dragging starts when you push mousedown and move mouse
},
drag:function(event, ui){
//this function will be called after drag started each time you move your mouse
}
stop:function(event, ui){
//this is where you release mouse button
}
})
this jquery draggable widget with droppable widget will ease your life if you really want to implement complex drag-and-drop functionality
I made this:
function drag(ev) { alert('Hi'); }
var grpcount = 21;
var group=$(document.createElement('div'));
group.attr({id: 'group'+grpcount});
group.attr({draggable: "true"});
group.addClass('group');
group.html("<span class='group'>Group"+grpcount+"</span>");
group.bind("dragstart", function(ev){drag(ev);});
$('#boundary').append(group);
See the working fiddle here: http://jsfiddle.net/nxcSz/

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