126

I am looking for a drag & DROP plugin that works on touch devices.

I would like similar functionality to the jQuery UI plugin which allows "droppable" elements.

The jqtouch plugin supports dragging, but no dropping.

Here is drag & drop that only supports iPhone/iPad.

Can anyone point me in the direction of a drag & drop plugin that works on android/ios?

...Or it might be possible to update the jqtouch plugin for droppability, it already runs on Andriod and IOS.

Thanks!

3
  • 1
    This is in progress, but I don't know what devices support it: This plugins.jquery.com/project/mobiledraganddrop ... have you looked through the jQuerymobile.com libraries? I also found this duplicate SO question: stackoverflow.com/questions/3172100/…
    – iivel
    Commented Mar 3, 2011 at 21:11
  • Thanks. Yeah mobiledraganddrop only supports click and drop on mobile devices. I could not find anything on jQuerymobile.com. The other question has an answer already marked as correct that refers to sencha.com/products/touch which has a limited source licence.
    – joe
    Commented Mar 3, 2011 at 21:28
  • I'm curious for one that works on mobile and desktop browsers.
    – Lime
    Commented Jun 15, 2011 at 18:34

5 Answers 5

268

You can use the Jquery UI for drag and drop with an additional library that translates mouse events into touch which is what you need, the library I recommend is https://github.com/furf/jquery-ui-touch-punch, with this your drag and drop from Jquery UI should work on touch devises

or you can use this code which I am using, it also converts mouse events into touch and it works like magic.

function touchHandler(event) {
    var touch = event.changedTouches[0];

    var simulatedEvent = document.createEvent("MouseEvent");
        simulatedEvent.initMouseEvent({
        touchstart: "mousedown",
        touchmove: "mousemove",
        touchend: "mouseup"
    }[event.type], true, true, window, 1,
        touch.screenX, touch.screenY,
        touch.clientX, touch.clientY, false,
        false, false, false, 0, null);

    touch.target.dispatchEvent(simulatedEvent);
    event.preventDefault();
}

function init() {
    document.addEventListener("touchstart", touchHandler, true);
    document.addEventListener("touchmove", touchHandler, true);
    document.addEventListener("touchend", touchHandler, true);
    document.addEventListener("touchcancel", touchHandler, true);
}

And in your document.ready just call the init() function

code found from Here

19
  • 11
    Thanks, on my Android device stuff is now draggable. However, the click event is not fired anymore when I click on it. Any ideas how to fix that? Commented Dec 2, 2011 at 8:58
  • 9
    Note: Since the event listener is registered for the whole document, this solution also disables scrolling on my Nexus S... Commented May 10, 2012 at 12:12
  • 30
    Thanks for sharing this. However, you should give credit to the original author of the code you have posted. ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript
    – undefined
    Commented May 18, 2012 at 0:22
  • 3
    @JohnLandheer I fixed the issue by attaching the event listeners only to the objects I wanted draggable, document.getElementById('draggableContainer').addEventListener(...
    – chiliNUT
    Commented Nov 5, 2013 at 21:34
  • 1
    Touch-punch is great. One of those 'it just works' things. Alas, it doesn't support dual-touch...which I'd love to see.
    – DA.
    Commented Jan 20, 2014 at 17:55
21

For anyone looking to use this and keep the 'click' functionality (as John Landheer mentions in his comment), you can do it with just a couple of modifications:

Add a couple of globals:

var clickms = 100;
var lastTouchDown = -1;

Then modify the switch statement from the original to this:

var d = new Date();
switch(event.type)
{
    case "touchstart": type = "mousedown"; lastTouchDown = d.getTime(); break;
    case "touchmove": type="mousemove"; lastTouchDown = -1; break;        
    case "touchend": if(lastTouchDown > -1 && (d.getTime() - lastTouchDown) < clickms){lastTouchDown = -1; type="click"; break;} type="mouseup"; break;
    default: return;
}

You may want to adjust 'clickms' to your tastes. Basically it's just watching for a 'touchstart' followed quickly by a 'touchend' to simulate a click.

5
  • @E. Z. Hart - could you please let me know where to put your code in above given code to enable click event ???
    – Valay
    Commented Nov 12, 2014 at 7:05
  • 1
    @ChakoDesai - The code in the answer has been edited heavily since I wrote my response. Check out stackoverflow.com/posts/6362527/revisions and look at the code from June 30, 2011; my answer will make a lot more sense based on that version.
    – E.Z. Hart
    Commented Nov 13, 2014 at 2:13
  • @E. Z. Hart - I've updated my code from the given url. But why sometimes click works and sometimes not ???
    – Valay
    Commented Nov 13, 2014 at 9:38
  • @ChakoDesai - Without seeing your code I can't be sure. You might want to open a new question for that.
    – E.Z. Hart
    Commented Nov 13, 2014 at 22:04
  • An updated answer to make the above code work with click events can be found here: stackoverflow.com/questions/28218888/… Commented Feb 2, 2015 at 15:03
12

Thanks for the above codes! - I tried several options and this was the ticket. I had problems in that preventDefault was preventing scrolling on the ipad - I am now testing for draggable items and it works great so far.

if (event.target.id == 'draggable_item' ) {
    event.preventDefault();
}
1
  • Have you tested this in Windows Phone? Or anything other than iPhone? From past experience, this seems to work perfect in iPhones/iPads, but doesn't work well in other devices, specially in Windows Phones. Commented Nov 25, 2016 at 4:49
10

I had the same solution as gregpress answer, but my draggable items used a class instead of an id. It seems to work.

var $target = $(event.target);  
if( $target.hasClass('draggable') ) {  
    event.preventDefault();  
}
2
  • 4
    The fact that you have simply used a different selector does not warrant being a separate answer, but instead you should have commented on @gregpress's answer.
    – bPratik
    Commented Sep 28, 2012 at 23:55
  • 2
    @bPratik unless he wanted the nicer formatting an answer provides -- and the fact that he provided an entire code example does warrant a separate answer. Should have left a comment linking to his answer though...
    – drzaus
    Commented Sep 3, 2013 at 18:34
8

Old thread I know.......

Problem with the answer of @ryuutatsuo is that it blocks also any input or other element that has to react on 'clicks' (for example inputs), so i wrote this solution. This solution made it possible to use any existing drag and drop library that is based upon mousedown, mousemove and mouseup events on any touch device (or cumputer). This is also a cross-browser solution.

I have tested in on several devices and it works fast (in combination with the drag and drop feature of ThreeDubMedia (see also http://threedubmedia.com/code/event/drag)). It is a jQuery solution so you can use it only with jQuery libs. I have used jQuery 1.5.1 for it because some newer functions don't work properly with IE9 and above (not tested with newer versions of jQuery).

Before you add any drag or drop operation to an event you have to call this function first:

simulateTouchEvents(<object>);

You can also block all components/children for input or to speed up event handling by using the following syntax:

simulateTouchEvents(<object>, true); // ignore events on childs

Here is the code i wrote. I used some nice tricks to speed up evaluating things (see code).

function simulateTouchEvents(oo,bIgnoreChilds)
{
 if( !$(oo)[0] )
  { return false; }

 if( !window.__touchTypes )
 {
   window.__touchTypes  = {touchstart:'mousedown',touchmove:'mousemove',touchend:'mouseup'};
   window.__touchInputs = {INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,'input':1,'textarea':1,'select':1,'option':1};
 }

$(oo).bind('touchstart touchmove touchend', function(ev)
{
    var bSame = (ev.target == this);
    if( bIgnoreChilds && !bSame )
     { return; }

    var b = (!bSame && ev.target.__ajqmeclk), // Get if object is already tested or input type
        e = ev.originalEvent;
    if( b === true || !e.touches || e.touches.length > 1 || !window.__touchTypes[e.type]  )
     { return; } //allow multi-touch gestures to work

    var oEv = ( !bSame && typeof b != 'boolean')?$(ev.target).data('events'):false,
        b = (!bSame)?(ev.target.__ajqmeclk = oEv?(oEv['click'] || oEv['mousedown'] || oEv['mouseup'] || oEv['mousemove']):false ):false;

    if( b || window.__touchInputs[ev.target.tagName] )
     { return; } //allow default clicks to work (and on inputs)

    // https://developer.mozilla.org/en/DOM/event.initMouseEvent for API
    var touch = e.changedTouches[0], newEvent = document.createEvent("MouseEvent");
    newEvent.initMouseEvent(window.__touchTypes[e.type], true, true, window, 1,
            touch.screenX, touch.screenY,
            touch.clientX, touch.clientY, false,
            false, false, false, 0, null);

    touch.target.dispatchEvent(newEvent);
    e.preventDefault();
    ev.stopImmediatePropagation();
    ev.stopPropagation();
    ev.preventDefault();
});
 return true;
}; 

What it does: At first, it translates single touch events into mouse events. It checks if an event is caused by an element on/in the element that must be dragged around. If it is an input element like input, textarea etc, it skips the translation, or if a standard mouse event is attached to it it will also skip a translation.

Result: Every element on a draggable element is still working.

Happy coding, greetz, Erwin Haantjes

5
  • which object should I pass in simulateTouchEvents(<object>, true); ???
    – Valay
    Commented Nov 12, 2014 at 7:25
  • For example: simulateTouchEvents( $('#yourid; ), true ); or simulateTouchEvents( document.getElementById('yourid') , true ); etc
    – Codebeat
    Commented Nov 13, 2014 at 0:33
  • could you please look at my another question link ???
    – Valay
    Commented Nov 17, 2014 at 10:15
  • Use threedubmedia.com/code/event/drag and disable x or y moving of element. When you use the code in this article you can 'scroll' the scrollbars. But do know why you want to do this because a page on mobile phone got already scrollbars. Don't understand what you want to do with it. Success!
    – Codebeat
    Commented Nov 17, 2014 at 10:54
  • I've to add drag-n-drop of columns and scrolling both. When I turn on touch events in chrome, I am not able to scroll the table. Not even on mobile.
    – Valay
    Commented Nov 17, 2014 at 11:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.