Javascript Drag and Drop: removing dragged element following successful drop - javascript

I'm using the native drag and drop API in javascript. How can I remove a dragged element from the DOM following a successful drop?
I've tried listening to the drop event, but this only gets fired on the element which is dropped onto and has no reference to the element being dragged.
I've tried listening to the dragend element, but this doesn't let me know whether a drop was successful or not.
I'm trying to avoid storing the element being dragged in a global variable as this will cause problems if a drag occurs between different tabs or browsers.
Here's an example: http://jsfiddle.net/KNG6n/3/
A list of letters which can be dragged into the box. When a letter's node is dropped on the box, I'd like it to be removed from the list (without effecting any other list items containing the same letter)

Listen for the dragend event and check the dropEffect variable of the dataTransfer object before doing anything with the dragged element:
htmlElement.addEventListener('dragend', function(event){
if(event.dataTransfer.dropEffect !== 'none'){
$(this).remove();
}
});

Also take a look at this example: http://html5demos.com/drag
var el = document.getElementById(e.dataTransfer.getData('Text'));
el.parentNode.removeChild(el);

One way would be to assign this to a variable scoped outside of the dragstart, and use that element when dropped.
See this fiddle.

You get the drop position of element in the dragend event. You can find if an droppable element is present at that position.
You can use document.elementFromPoint(x, y);

Related

jQuery UI - programatically move a dropped draggable to another "available" droppable

I have a mini form control where I drag several draggables onto a scale. See my plunk
Ideally, whenever I drop a draggable, I would like to do in the stop( event, ui ) method:
check if the droppable already has a draggable (let's call it draggable2)
if there is draggable2, I would like to scan my droppables for one that does not have a draggable
then move draggable2 to this droppable
Are there APIs/ways to do this programmatically? I know this sounds similar to sortables, but I am strictly looking for the ability to
move a draggable to a droppable
and
to know if a droppable already has a draggable, and be able to identify the draggable
Any help will be greatly appreciated. Thank you.
I have found a way to accomplish this. Although there are no options from the jQuery UI draggables/droppables API, I have managed to track the draggables and droppables by adding unique "id" attributes to track them.
Here is how I approached the following:
move a draggable to a droppable
My approach: Find the coordinates of the target droppable, and update the css of the draggable.
To figure out which dragger was dragged and which dropper received it, I added attributes dragger-id and dropper-id so I could identify them during the drop event:
drop: function( event, ui ){
// Get the current dragger and dropper ID's
dropperId = $(this).attr('dropper-id');
draggerId = ui.draggable.attr('dragger-id');
// ... more code
}
then I calculated the top and left coordinates for the dragger based on the droppable's values. For this, I used the jQuery's offset() method.
drop_x = $('.droppable').offset().left - $('.draggable').offset().left;
drop_y = $('.droppable').offset().top - $('.draggable').offset().top;
Note: I had to do a difference calculation since draggables are positioned relative to where they start.
Finally, I set the top and left css values:
ui.draggable.css('top', drop_y+'px'); // y-axis
ui.draggable.css('left', drop_x+'px'); // x-axis
to know if a droppable already has a draggable, and be able to identify the draggable
For this, I created yet another attribute on the droppable elements to track the dragger-id values. I called it current-dragger so that it would be unique and I could query by it. I used -1 as my default value, meaning "no dragger".
I assigned current-dragger in the drop method as well:
drop: function( event, ui ){
// Get the current dragger and dropper ID's
dropperId = $(this).attr('dropper-id');
draggerId = ui.draggable.attr('dragger-id');
// Remove current-dragger value from old dropper (-1 means no dragger)
$('[current-dragger="' + draggerId + '"]').attr('current-dragger', '-1');
// Update current-dragger on this dropper
$(this).attr('current-dragger', draggerId);
// ... more code
}
I suppose there's really no need to do updates to the DOM attributes, so in prod I will be tracking the current dragger inside of a JavaScript mapping object.
For a full working example, see my updated plunk

Cloned draggable with deepWithDataAndEvents = true unable to be dragged again

I want to be able to:
Clone draggables and be able to re-drag them
Keep data & events associated to the initial draggable div
Currently, with the .clone method set to clone(), the cloned draggable can be dragged but understandably the clone does not retain data from the initial draggable.
If clone(true) is used, the cloned draggable retains data from the initial draggable but cannot be dragged.
var dropped = jQuery(ui.draggable).clone().addClass("dropped").draggable(); //No data
var dropped = jQuery(ui.draggable).clone(true).addClass("dropped").draggable(); //Not draggable
Would anyone have any ideas what the problem might be? Any help is greatly appreciated. Here is the jsFiddle I have been working on - http://jsfiddle.net/wc71z5to/
If you are able to update to a slightly later version of jQuery (I use 19.2. in the JSFiddle), you can use delegated events for the click and not worry about using a deep clone.
http://jsfiddle.net/TrueBlueAussie/wc71z5to/2/
jQuery(document).on('click', '.component', function() {
alert($( this ).data( 'name' ));
});
It is not 100% obvious from the example what it is you need to retain, behaviour-wise, from the clones. If you can clarify I will try to ensure this meets your needs :)
A delegated event works by listening for events bubbling up to a non-changing ancestor. document is the default if there is nothing convenient/closer. It then applies the jQuery selector to the elements in the bubble chain. It then calls the function for any matching element that caused the event. This means the element does not have to match until event time, rather than when the event handler is created.
Note: Do not use 'body' for delegated events, as styling can cause the body to have 0 height and events may not occur! Always use document as the fallback.

Events using $(this)

My issue here is primarily jQuery...
I'm wanting to have events fire when a certain interaction is carried out however... only for "this" particular item provided all items are identical.
Firstly I'm not sure why the hover state is not firing - the console log shows the interaction is there however, not triggering the div to appear. I need the "show-me" div to appear when only hovered on the span and mouseoff for the div to disappear.
Also when the user clicks "select" for the options to ONLY hide for the current item input they selected - not all options to hide.
I'm having trouble trying to find a way to select elements that are somewhat out of scope as .find() will only find descendants - I want to have my mark up elsewhere and be able to select the element regardless of where it's location is within the markup.
Here is a JSFIDDLE of a working example for you to potentially "fiddle" with ;-)
All suggestions welcome!
Here is my jQuery
//Show item on hover for current item hovered
var item = $('.item'),
itemShow = $('.show-me');
item.hover(function() {
$(this).nextAll('.show-me').show();
console.log("hovered");
}, function() {
$(this).nextAll('.show-me').hide();
});
//Click select to hide options
$('.item').find('input').on('click', function() {
$(this).nextAll('ul').hide();
console.log("select was clicked");
});
Your tree traversal is incorrect using nextAll which is for siblings.... use find() for descendents
$(this).find('.show-me').show();
DEMO
Refer to API Docs
In addition to charlie's answer, you may also use .children(),
$(this).children('.show-me').show();
JSFIDDLE

JQuery UI - Append Draggable to Droppable

How do you append an item being dragged to a target element on drop, using jQueryUI's draggables/dropables? It looks like the way jQuery UI works right now is it just moves the items around on the screen via absolute positioning. Unfortunately, this functionality makes form submissions useless, as you cannot get the positions of the values on submission.
Thanks in advance for any items/pointers!
If I understood correctly, you want the dragged element to be detached from it's current parent and be appended to the new one, right? You can use a helper to do the dragging (so the original element is not affected) and, upon drop, detach it and append it to the target (thanks #Oleg and #Brian for improving over my original answer).
$(myDraggable).draggable({
helper:"clone",
containment:"document"
});
$(myDroppable).droppable({
drop:function(event, ui) {
ui.draggable.detach().appendTo($(this));
}
});
​
Working example at jsFiddle

jQuery UI Draggable - need to modify element while dragging

I'm playing with Drag and drop funcitonality for the first time so I'm not entirely sure what I'm doing!
I need to add a class to a "portlet" while it is being dragged. I don't want to use the clone functionality because I want the user to drag the actual element, I just want to nodify the element while it is being dragged and reset it when it's dropped.
Can anybody help?
Perhaps there's some sort of a 'beforedrag' event you can bind to? It would be easier to add the class to an element before the user actually starts dragging it, rather than during.
If you're using jQuery UI, there's a 'start' event on draggable you can use:
http://docs.jquery.com/UI/Draggable#events
Also, you can use the "helper" option like this:
helper : function(ev, el) {
return ($(el).clone().addClass("beingDragged"));
}
Should your portlets become in the future too heavyweight to drag, you could use that to build a simplified version while dragging to smooth things out :)

Categories