javascriptcssdraggablemousemovetouchstart

Draggable toggle checkboxes events not firing on Chrome (JS/CSS)


I'm trying to replicate as closely as possible the sliding toggles of iOS, using just JS and CSS. I've found the excellent pen by @3rror404 that does exactly that here.

While it works perfectly in iOS Safari , it does react just to clicks and not to drags in Chrome (both Desktop and Android) and I don't understand why. I even added mouseup/mousedown/mousemove events, but still a no go..

for (let i = 0; i < switches.length; i++) {

  const switchEl = switches[i];

  switchEl.draggable = true;

  ['dragstart', 'touchstart','mousedown'].forEach(function(e) {
    switchEl.addEventListener(e, onDragStart);
  });

  ['dragover', 'touchmove','mousemove'].forEach(function(e) {
    switchEl.addEventListener(e, onDragOver);
  });

  ['dragend', 'touchend','mouseup'].forEach(function(e) {
    switchEl.addEventListener(e, onDragEnd);
  });

}

see my edited pen here: https://codepen.io/azerty1234/pen/BajLqgN

any idea why this happens or possible fixes? Thanks!


Solution

  • I found a bug in the pen.

    It adds the same event handler for dragstart and touchstart Chrome (in mobile mode) fires the touchstart event.

    The touchstart event does not have a pageX and pageY variable (line 64 and 65)

    It does have evt.touches[0].pageX and evt.touches[0].pageY

    You should check if evt.type equals 'touchstart' or not:

    function onDragStart(evt) {
      evt = evt || window.event;
      const x = (evt.type == 'touchstart') ? evt.touches[0].pageX : evt.pageX,
            y = (evt.type == 'touchstart') ? evt.touches[0].pageY : evt.pageY;
    ...
    
    function onDragOver(evt) {
      evt = evt || window.event;
    
      evt.preventDefault();
      const x = (evt.type == 'touchmove') ? evt.touches[0].pageX : evt.pageX,
            y = (evt.type == 'touchmove') ? evt.touches[0].pageY : evt.pageY;
    ...
    

    Apply this change in onDragOver (64,65) and onDragStart (90,91) and it will work in mobile mode