Search code examples
javascripttouchdom-events

JavaScript touchend on dynamically shown element doesn't fire


I noticed a strange behavior in touch events. The situation is like that: I have a #pointercapture div, which is hidden by default. A touchstart handler is attached to the body, which causes pointercapture to show (overlays the body). The pointercapture has touchend event attached, which hides it. The issue is that on touchstart pointercapture appears and on touchend it doesn't hide. You have to touch screen and release once more for this to disappear. Here's the fiddle. I have also attached mouse events, which work as expected (pointercapture hides on first mouseup). https://jsfiddle.net/3p8eyug5/

HTML

<body>
<div id="pointercapture"></div>
</body>

CSS

body {
  width:500px;
  height:500px;
  background:green;
}
#pointercapture {
  display:none;
  position:fixed;
  top:0;
  left:0;
  right:0;
  bottom:0;
  background:orange;
}

JavaScript

  var $=jQuery;
$('body').on('touchstart mousedown', function(e) {
    $('#pointercapture').show();
    e.preventDefault();
});

$('#pointercapture').on('touchend mouseup', function(e) {
    $(this).hide();
    e.preventDefault();
});

Can someone explain this behavior? I'm also curious how it works with pointer events and touch, I have no way to check it now.


Solution

  • This is expected behavior. Once the body captures the touchstart event it holds the entire touch action through touchend (The touch event is not transfered to #pointercapture when it appears). You just need to put the touchend event on the body instead of #pointercapture and it should work as you describe.

    $('body').on('touchstart mousedown', function(e) {
        $('#pointercapture').show();
        e.preventDefault();
    });
    
    $('body').on('touchend mouseup', function(e) {
        $('#pointercapture').hide(); // also change this to #pointercapture
        e.preventDefault();
    });
    

    https://jsfiddle.net/3p8eyug5/1/