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!
Related
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/
I am trying to create draggable objects that have each have their own properties. I am a beginner at Javascript with very minimal experience, and this is for a project that involves creating a simple circuit simulator.
So far, I have been able to drag, drop & clone components in a DOM courtesy of some very helpful stackoverflow-ers. But I am struggling to move on to the next bit, which is making each component unique, with editable properties such as name, type and coordinates, so that when I click on that object again, I can pull up something like a little pop-up menu that allows me to modify the properties of that specific object.
Would anyone be able to offer any pointers of how to go about doing it?
Here is the jsfiddle of what I have so far - http://jsfiddle.net/3Lnqocf3/
Any help is very much appreciated!
Javascript -
jQuery(function() {
jQuery(".component").draggable({
// use a helper-clone that is append to 'body' so is not 'contained' by a pane
helper: function() {
return jQuery(this).clone().appendTo('body').css({
'zIndex': 5
});
},
cursor: 'move',
containment: "document"
});
jQuery('.ui-layout-center').droppable({
activeClass: 'ui-state-hover',
accept: '.component',
drop: function(e, ui) {
if (!ui.draggable.hasClass("dropped")) {
var parentOffset = jQuery('.ui-layout-center').offset();
var dropped = jQuery(ui.draggable).clone().addClass("dropped").draggable();
dropped.css('left', (ui.position.left - parentOffset.left) +'px');
dropped.css('top', (ui.position.top - parentOffset.top) +'px');
jQuery(this).append(dropped);
}
}
});
});
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/
Basically, I have .dragme (object being dragged), .dropzone1 (place to be dropped at) and an image I want .dragme to become once it has been dropped.
So far I have this
$(".dropzone1").droppable({
accept:".dragme",
drop: function() {
alert("DROPPED");
}
});
So, that code works, once .dragme has been dropped in place I get the alert. But I've tried using .attr to change the image source of .dragme in place of where the alert is currently (the alert also works if I put it into the below code, but the image still doesn't change):
$(".dropzone1").droppable({
accept:".dragme",
drop: function() {
$(".dragme").attr("src", "../imgs/newimage.png");
}
});
I've looked through other answers to similar questions, but none of the solutions worked, any help is greatly appreciated.
This is a little jsfiddle but i can't get my images onto it, they're only 30x30 png's anyway. I made it so that the alert is working so if anyone can have a play and get it so that the red block changes colour or into an image when it lands on the blue, that'd be great!
Try this:
demo
$(".dragme").draggable();
$(".dropzone1").droppable({
accept:".dragme",
drop: function( event, ui ) {
$(".dragme").attr("src", "../imgs/newimage.png");
alert($(".dragme").attr('src'));
}
});
2nd Solution
DEMO
$(".dragme").draggable();
$(".dropzone1").droppable({
accept:".dragme",
drop: function( event, ui ) {
$(ui.draggable).attr("src", "../imgs/newimage.png");
}
});
From the drop event documentation:
This event is triggered when an accepted draggable is dropped 'over' (within the
tolerance of) this droppable. In the callback, $(this) represents the droppable
the draggable is dropped on. ui.draggable represents the draggable.
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 ;)