How can I make a jQuery UI 'draggable()' div draggable for touchscreen?
Asked Answered
B

7

117

I have a jQuery UI draggable() that works in Firefox and Chrome. The user interface concept is basically click to create a "post-it" type item.

Basically, I click or tap on div#everything (100% high and wide) that listens for clicks, and an input textarea displays. You add text, and then when you're done it saves it. You can drag this element around. That is working on normal browsers, but on an iPad I can test with I can't drag the items around. If I touch to select (it then dims slightly), I can't then drag it. It won't drag left or right at all. I can drag up or down, but I'm not dragging the individual div, I'm dragging the whole webpage.

So here's the code I use to capture clicks:

$('#everything').bind('click', function(e){
    var elem = document.createElement('DIV');
    STATE.top = e.pageY;
    STATE.left = e.pageX;
    var e = $(elem).css({
        top: STATE.top,
        left: STATE.left
    }).html('<textarea></textarea>')
    .addClass('instance')
    .bind('click', function(event){
        return false;
    });
    $(this).append(e);
});

And here's the code I use to "save" the note and turn the input div into just a display div:

$('textarea').live('mouseleave', function(){
    var val = jQuery.trim($(this).val());
    STATE.content = val;
    if (val == '') {
        $(this).parent().remove();
    } else {
        var div  = $(this).parent();
        div.text(val).css({
            height: '30px'
        });
        STATE.height = 30;
        if ( div.width() !== div[0].clientWidth || div.height () !== div[0].clientHeight ) {
            while (div.width() !== div[0].clientWidth || div.height () !== div[0].clientHeight) {
                var h = div.height() + 10;
                STATE.height = h;
                div.css({
                    height: (h) + 'px'
                });     // element just got scrollbars
            }
        }
        STATE.guid = uniqueID()
        div.addClass('savedNote').attr('id', STATE.guid).draggable({
            stop: function() {
                var offset = $(this).offset();
                STATE.guid = $(this).attr('id');
                STATE.top = offset.top;
                STATE.left = offset.left;
                STATE.content = $(this).text();
                STATE.height = $(this).height();
                STATE.save();
            }
        });
        STATE.save();
        $(this).remove();
    }
});

And I have this code when I load the page for saved notes:

$('.savedNote').draggable({
    stop: function() {
        STATE.guid = $(this).attr('id');
        var offset = $(this).offset();
        STATE.top = offset.top;
        STATE.left = offset.left;
        STATE.content = $(this).text();
        STATE.height = $(this).height();
        STATE.save();
    }
});

My STATE object handles saving the notes.

Onload, this is the whole html body:

<body> 
    <div id="everything"></div> 
<div class="instance savedNote" id="iddd1b0969-c634-8876-75a9-b274ff87186b" style="top:134px;left:715px;height:30px;">Whatever dude</div> 
<div class="instance savedNote" id="id8a129f06-7d0c-3cb3-9212-0f38a8445700" style="top:131px;left:347px;height:30px;">Appointment 11:45am</div> 
<div class="instance savedNote" id="ide92e3d13-afe8-79d7-bc03-818d4c7a471f" style="top:144px;left:65px;height:80px;">What do you think of a board where you can add writing as much as possible?</div> 
<div class="instance savedNote" id="idef7fe420-4c19-cfec-36b6-272f1e9b5df5" style="top:301px;left:534px;height:30px;">This was submitted</div> 
<div class="instance savedNote" id="id93b3b56f-5e23-1bd1-ddc1-9be41f1efb44" style="top:390px;left:217px;height:30px;">Hello world from iPad.</div> 

</body>

So, my question is really: how can I make this work better on iPad?

I'm not set on jQuery UI, I'm wondering if this is something I'm doing wrong with jQuery UI, or jQuery, or whether there may be better frameworks for doing cross-platform/backward compatible draggable() elements that will work for touchscreen UIs.

More general comments about how to write UI components like this would be welcome as well.

Thanks!


UPDATE: I was able to simply chain this onto my jQuery UI draggable() call and get the correct draggability on iPad!

.touch({
    animate: false,
    sticky: false,
    dragx: true,
    dragy: true,
    rotate: false,
    resort: true,
    scale: false
});

The jQuery Touch plugin did the trick!

Blanchard answered 11/6, 2010 at 23:46 Comment(6)
I'm curious about something: can you drag the div around with two or three fingers? I know that you have to sometimes use multiple fingers to scroll embedded content in mobile Safari, so it may be the same for "draggable" content.Cress
Walter Mundt thanks! I have not tried any variations of fingers, I will try when I get it in my hands!Blanchard
two or three fingers actually prevented the "whole page" from inadvertently scrolling, but made no change for the draggable.Blanchard
This technique did not seem to work for me, unfortunately. :(Jacklighter
@Jacklighter You'll need to look at some of the other answers for other possible solutionsBlanchard
This plugin works perfectly for me (draggable and resizable): github.com/furf/jquery-ui-touch-punch. Demo here furf.com/exp/touch-punch. The code works for BOTH regular browser and Android (iOS not tested) at the same time.Pavyer
C
144

After wasting many hours, I came across this!

jquery-ui-touch-punch

It translates tap events as click events. Remember to load the script after jquery.

I got this working on the iPad and iPhone

$('#movable').draggable({containment: "parent"});
Cyanate answered 7/2, 2012 at 10:34 Comment(4)
This solution works great, another answer I tired was buggy and really didn't helpOutfielder
A small tip: works great, although if the draggable element covered with layers like an image with a mask above it no drag is activated but the solution will be the add pointer-events:none; on the top layers.Sitin
This is a great and simple solution, you just use the plugin and continue working with the JQuery draggable function. Perfect, thanks!Snick
This will prevent clickable items within the draggable.Aylward
M
62

Caution: This answer was written in 2010 and technology moves fast. For a more recent solution, see @ctrl-alt-dileep's answer below.


Depending on your needs, you may wish to try the jQuery touch plugin; you can try an example here. It works fine to drag on my iPhone, whereas jQuery UI Draggable doesn't.

Alternatively, you can try this plugin, though that might require you to actually write your own draggable function.

As a sidenote: Believe it or not, we're hearing increasing buzz about how touch devices such as the iPad and iPhone is causing problems both for websites using :hover/onmouseover functions and draggable content.

If you're interested in the underlying solution for this, it's to use three new JavaScript events; ontouchstart, ontouchmove and ontouchend. Apple actually has written an article about their use, which you can find here. A simplified example can be found here. These events are used in both of the plugins I linked to.

Menorca answered 15/6, 2010 at 6:18 Comment(8)
Super awesome! All I had to do was to chain on .touch({ animate: false, sticky: false, dragx: true, dragy: true, rotate: false, resort: true, scale: false }); to my existing draggable() call and it works a treat! I still have to work out all the events I want to deal with to get the workflow right, but the jQuery touch plugin did the trick!Blanchard
Excellent first use of the bounty system. Thanks! I'll also be looking at other ways to do this. Hoping the jQueryUI guys can integrate the touchscreen support though. Seems like an obvious addition.Blanchard
Yeah, I fully agree that touchscreen support would be a good addition to jQuery UI. Glad to be of help!Menorca
the plugin does not seem to be available on jquery.com any more. you can still find the javascript here manifestinteractive.com/iphone/touch/js/jquery.touch.jsShod
Any plugin that implemnts droppable elements? You can drag with jquery touch but you cant drop!Rafaelita
Heh, now the plugin is missing from manifestinteractive.com, too. Try this: plugins.jquery.com/files/jquery.touch.js.txtMelia
this answer is no longer valid. see @ctrl-alt-dileep's answer below (jquery-ui-touch-punch) for a 2012 answerShod
@Shod Thanks for pointing this out. I've updated my answer with a warning. :)Menorca
B
24

This project should be helpful - maps touch events to click events in a way that allows jQuery UI to work on iPad and iPhone without any changes. Just add the JS to any existing project.

http://code.google.com/p/jquery-ui-for-ipad-and-iphone/

Bristling answered 2/9, 2010 at 3:45 Comment(0)
E
7

jQuery ui 1.9 is going to take care of this for you. Heres a demo of the pre:

https://dl.dropbox.com/u/3872624/lab/touch/index.html

Just grab the jquery.mouse.ui.js out, stick it under the jQuery ui file you're loading, and that's all you should have to do! Works for sortable as well.

This code is working great for me, but if your getting errors, an updated version of jquery.mouse.ui.js can be found here:

Jquery-ui sortable doesn't work on touch devices based on Android or IOS

Entwine answered 30/8, 2011 at 18:31 Comment(2)
This is great they are dealing with this 1.9. FWIW, I found the version of the code in that demo had bugs in it though and didn't work that well. Someone posted a more correct version on this question: #6745598 that is working better for me.Historiography
I updated my answer to address this. I haven't gotten any errors in my use case with the original yet.Entwine
T
4

This project on github may be your solution

https://github.com/furf/jquery-ui-touch-punch

Talkathon answered 9/7, 2012 at 2:3 Comment(0)
C
2

I was struggling with a similar problem yesterday. I already had a "working" solution using jQuery UI's draggable together with jQuery Touch Punch, which are mentioned in other answers. However, using this method was causing weird bugs in some Android devices for me, and therefore I decided to write a small jQuery plugin that can make HTML elements draggable by using touch events instead of using a method that emulates fake mouse events.

The result of this is jQuery Draggable Touch which is a simple jQuery plugin for making elements draggable, that has touch devices as it's main target by using touch events (like touchstart, touchmove, touchend, etc.). It still has a fallback that uses mouse events if the browser/device doesn't support touch events.

Contagious answered 6/2, 2013 at 16:55 Comment(1)
Hi Heyman, That's nice work. Thanks for sharing it. Will it work for jQuery resizable too ?Ossa
T
2

You can try using jquery.pep.js:

jquery.pep.js is a lightweight jQuery plugin which turns any DOM element into a draggable object. It works across mostly all browsers, from old to new, from touch to click. I built it to serve a need in which jQuery UI’s draggable was not fulfilling, since it didn’t work on touch devices (without some hackery).

Website, GitHub link

Torsibility answered 14/10, 2014 at 13:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.