Jump to content


Draggable – Hold to drag

Moderator Tag

Recommended Posts


 Hey guys, I find myself in a pretty interesting UI challenge that I think Draggable might be able to solve. I will try to explain it as clearly as possible. Here's what I want to do – on both mobile and desktop:


1. Have a list of edge-to-edge elements (Think the contacts list on iOS without the separators) that the user can scroll through normally.


2. Allow the user to tap / click and select/deselect the list items


3. Hold the finger or mouse button down for 800ms and initiate drag/drop so that the items can be re-ordered.


The main problem is having drag and native scroll at the same time on mobile devices. Quite naturally because Draggable uses the touch events to perform its dragging magic, so when you try to scroll the list, you instead throw the list items around.


I plan on tackling this one by setting up my own mousedown / touchstart listener and combine it with a timer that would then create a new Draggable instance if the mouse/finger is still pressed after the 800ms. At that point I could forward the mouse position via an event to the new draggable.startDrag() method and have it drag instantly after being created.


From what I can tell, this would be the simplest way to solve my problem, but I just wanted to make sure this logic isn't part of Draggable as is, and that the problem hasn't already been solved for me. 


Link to comment
Share on other sites



In fact Draggable doesn't have any timer into it to trigger any functionality, it works based on how many pixels the mouse/touch moves after mousedown/touchstart, three pixels actually to keep the click possible.


What you could do is create the draggable instance and store it in a variable, right after you can disable the instance and with a TweenMax instance's onComplete callback you can enable it, why a Tween instance because any other timing element can't be stopped on mouseup, if the user makes a mistake and holds on the wrong element a setTimeout would continune, with a tween instance you can pause it and when the user goes to that element again it can start from zero. Finally when the drag is over you can add a call to disable the draggable instance again:

var timerObj = {a:0},
    element = $("#elementID"),
    timerTween = TweenMax.to(timerObj, 0.8, {a:1, onComplete:enableDrag}),
    dragInstance = Draggable.create(element,
    //draggable vars
    onDragEnd: disableDrag

//Disable the drag instance immediately

function disableDrag()

function enableDrag()





Link to comment
Share on other sites

  • 1 month later...

Thanks for the suggestion Rhenando, 


From reading the code though, I'm not sure this would work. I need to immidiately start dragging after the presshold, so I'm working on an solution where i let hammer.js handle the presshold event (As it works on both desktop and mobile) and in the event callback I activate Draggable and create a fake drag event so that the dragging starts immidiately.  


Will post a simplified version of my code if it works.

  • Like 1
Link to comment
Share on other sites

Alright, my solution worked. I put up a simplified version of what i did on GitHub:





Source code



I wrapped it in a ListSorter class that is easy to extend, for anyone in the same boat. For my own use case, I also created all of the logic for re-shuffling items so you get a true sortable list UI, but that's coupled together with a whole Backbone.js Model, View, Controller setup, and would probably be more confusing than helpful, if you use something other than Backbone, so I kept it short and sweet instead (57 lines).


You'll find a  CoffeeScript file as well as the compiled JavaScript.


Quick walk-through:

(Line numbers and links are to the CoffeeScript version, but it should be simple following along in the compiled JavaScript version)

Line 5 sets up the hold listener using hammer.js

Line 8 creates the draggables and immediately starts dragging the pressed down element


From here on Draggable does it's thing and in it's onDragEnd() callback the draggables are destroyed and the hold event listener is set up once again. 


I also added in a destroy() method that will remove all event listeners, and any inline styling, that was applied by draggable.

  • Like 3
Link to comment
Share on other sites

Great job


Thank you for sharing your solution with the community.


Happy tweening!!

Link to comment
Share on other sites

  • 9 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.