8

I am working on a Javascript / html5 project for iPad.

I need to be able to catch touchmove events on an element that does not get added to the DOM until after a touchstart event has fired (i.e. until after a person has put their finger on the screen.)

I have tried simulating a touchstart event and firing it programatically...

$( "#container" ).append( element );
element.on( "touchmove", doStuff );
var ev = $.Event( "touchstart" );
element.trigger( ev );

...however this does not work. The only way I can get doStuff to start firing is to lift my finger and then touch the screen again, triggering a second touchstart event.

How can I catch touchmove events on an element that is added to the DOM after my finger is already on the screen?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
user1031947
  • 6,294
  • 16
  • 55
  • 88
  • Is it possible to create a simplified version of this issue on http://jsfiddle.net ? I am not too familiar with the draggables but if I can play around with it, maybe we can figure something out – Huangism Sep 18 '14 at 19:02
  • Sure, fiddle here: http://jsfiddle.net/rx4qdtuj/3/ – user1031947 Sep 18 '14 at 19:19
  • I am not sure about the triggering of the event but if your goal is to move the box when your finger moves for the first time you touch then you might have to get the x and y of the mouse/touch and move the box accordingly – Huangism Sep 18 '14 at 19:30
  • The goal is not to drag - my original wording was wrong - the goal is get the touchmove event to start firing on the new element, when my finger brushes over it - without having to lift my finger and put it down again. For a number reasons I cannot listen to touchstart / touchmove events on a parent element instead - it has to be on the element that is newly added. – user1031947 Sep 18 '14 at 19:32
  • Oh I see, well I can get it to trigger once but it will not recognize the movement from your initial touch – Huangism Sep 18 '14 at 19:43
  • Yes, movement from the initial touch is what I need. – user1031947 Sep 18 '14 at 19:48
  • Something like [this](http://jsfiddle.net/myh68yno/) maybe? – Roamer-1888 Sep 18 '14 at 20:52
  • Any reason you don't accept Roamer-1888's solution? – ChocolateAndCheese Dec 15 '14 at 22:31

3 Answers3

6

To summarise, you appear to want :

  • on touchstart: to display and position a styled div element.
  • on touchmove: to drag the element without releasing and re-pressing the mouse button.

If this interpretation is correct, then the answer is to to handle touchmove events on the same element that was originally clicked on - namely the "body" element. It is not necessary to handle touchmove events of the element you want to drag (the added element).

There must be many ways to write the code. Here's one, which is probably not exactly what you want (chiefly in the positioning maths) but should be simple to adapt :

var $element = $("<div class='element' />");

$("body").on({
    'touchstart mousedown': function (e) {
        $element.appendTo("body");
        $(this).on('touchmove mousemove', move);
        move(e);//you could do `$(this).trigger('touchmove', e)` but a conventional function call keeps `move` simple.
    },
    'touchend mouseup': function (e) {
        $(this).off('touchmove mousemove');
    }
});

function move(e) {
    $element.css({
        left: (e.pageX - 10) + 'px',
        top: (e.pageY - 10) + 'px',
        cursor: 'pointer'
    });
}

mousedown/mousemove/mouseup allow for desktop testing and can be removed for touch device usage.

DEMO

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
0

If you just need it to trigger once then it is quite easy

function addElement() {
    $( "body" ).append( element );

    element.on( "touchmove", doStuff );
    element.trigger("touchmove"); 
}

http://jsfiddle.net/rx4qdtuj/8/

I checked this on my ipad simulator. I replaced the alert with append so you don't get constantly alerted on ipad.

If you want it to continually trigger, the only possible thing I can think of was to fake the touchmove on the created element

http://jsfiddle.net/rx4qdtuj/9/

var element = $("<div class='element' />");

$( "body" ).on( "touchstart", addElement );
$(".wrapper").on("touchmove", addElement);

function addElement() {
    $( "body" ).append( element );

    element.on( "touchmove", doStuff );
    element.trigger("touchmove"); 
}

function doStuff() {
    $('body').append('a ')
}

HTML

<div class="wrapper"></div>

CSS

.wrapper {
    position: absolute;
    top: 100px;
    left: 100px;
    width: 300px;
    height: 300px;
}

The move actually triggers on the already created div wrapper which is in the same spot as the created element

Huangism
  • 16,278
  • 7
  • 48
  • 74
  • Unfortunately I need touchmove to fire on it's own, and repeatedly. – user1031947 Sep 18 '14 at 19:55
  • Ahh - I see. Unfortunately this doesn't work in my case either. I cannnot listen to events on a parent element instead (complicated...) I can only listen to events on the element that is added to the DOM. – user1031947 Sep 18 '14 at 19:56
  • 1
    @user1031947 why not? this element exists for the sole purpose of capturing touchmove. You can use it to do whatever it is needed to the just created element. As a matter of fact, it can be removed after the touchmove has finished. Sorry it is not a parent, it's just another element that is placed at the same place as the created element – Huangism Sep 18 '14 at 19:58
  • Because IRL this is a webView that is embedded in a steroidsJS layer that does not become visible until after a touchstart event happens in a separate steroids layer. This is kind of the same as if you have your finger on the screen before the page is loaded and initializes - and then need to detect touchmove events on that once the page has finished initializing, without lifting your finger and putting it down again. – user1031947 Sep 18 '14 at 20:00
  • @user1031947 then honestly I don't think this is an issue at all. If the person has his finger on the screen before anything started to happen, that person would be smart enough to know he needs to do something before anything else starts to happen – Huangism Sep 18 '14 at 20:02
  • 1
    I'm not here to debate workflow - I am just wondering if it is possible to do this. Appreciate your help regardless. – user1031947 Sep 18 '14 at 20:06
  • @user1031947 I am just saying you might be worried over nothing. I don't think it's possible but I don't really know anything about the js lib that you are using – Huangism Sep 18 '14 at 20:07
  • Thanks - yes it is a bit of a pain and if I can't figure it out I'll have to rethink things a bit. I'll let this question sit for awhile and see if any other suggestions come up. – user1031947 Sep 18 '14 at 20:09
-3

see documentation draggable function

applicate you function

<div id="track" class="track">
<div id="box2" style="left:0; top:0">Drag Me</div>
</div>

native javascript

window.addEventListener('load', function(){

 var box2 = document.getElementById('box2'),
 boxleft, // left position of moving box
 startx, // starting x coordinate of touch point
 dist = 0, // distance traveled by touch point
 touchobj = null // Touch object holder

 box2.addEventListener('touchstart', function(e){
  touchobj = e.changedTouches[0] // reference first touch point
  boxleft = parseInt(box2.style.left) // get left position of box
  startx = parseInt(touchobj.clientX) // get x coord of touch point
  e.preventDefault() // prevent default click behavior
 }, false)

 box2.addEventListener('touchmove', function(e){
  touchobj = e.changedTouches[0] // reference first touch point for this event
  var dist = parseInt(touchobj.clientX) - startx // calculate dist traveled by touch point
 // move box according to starting pos plus dist
 // with lower limit 0 and upper limit 380 so it doesn't move outside track:
  box2.style.left = ( (boxleft + dist > 380)? 380 : (boxleft + dist < 0)? 0 : boxleft + dist ) + 'px'
  e.preventDefault()
 }, false)

}, false)
alessandrio
  • 4,282
  • 2
  • 29
  • 40