Click event fired twice on touch device

27
October 22, 2019, at 4:10 PM

I have a checkbox in a sortable div where the click or changed event is triggered twice on touch devices but not on desktop (nor simulating touch on Firefox dev tools) for some obscure reason. The unwanted effect is the checkbox being toggled twice in a row leaving it at its original state. I mention the div is sortable because when they are made no longer sortable the checkbox works just fine. Here is the relevant part:

$sortable.sortable({
    items: '.sortable',
    cancel: 'input,textarea,button,select,option'
});

I have no idea why the sortable widget makes the click event be fired twice.

My attempts to handle this have been unsuccessful:

I've tried disabling the default behavior of toggling a the checkbox and setting its value manually. However for some reason the checkbox won't be checked/unchecked. If I do it via console it does work:

// same with the "change" event
// the reason the event is bound to $sortable rather than the inputs themselves is that 
// new sortable divs are added dynamically so otherwise they wouldn't have the event bound to them
$sortable.on('click', 'input[type="checkbox"]', function (e) {
  e.stopImmediatePropagation();
  // this does disable the default behavior of checking/unchecking the box
  e.preventDefault();
  const $this = $(this);
  // this doesn't check/uncheck the box at all, but setting a global variable to $this and doing it via console does work
  $this.prop('checked', !$this.prop('checked'));
});

I have tried a more typical approach using a flag, however there seems to be some race condition (or whatever it's called because if I am not mistaken js is monothreaded) and the function is run twice anyway:

let checked = false;
$sortable.on('click', 'input[type="checkbox"]', function() {
  if (checked) return;
  // this is output twice, which is not what we are after
  console.log('running');
  checked = true;
  // here ideally we would set the value of the checkbox
  checked = false;
});

I have checked for any problematic events bound to the inputs using $._data($checkboxes[0], 'events') but other than a boostrap tooltip (mouseover and mouseout events) and of course the change event there's nothing else fishy.

edit: basically it seems that the sortable widget produces a separate click event when you click anywhere in the div or its children. That's the reason why click/change is fired twice. My question is: how can I discriminate between the originator of the event so that if it's the sortable plugin the event can be ignored, while if it's the listener I set up the checkbox does change its value (and I perform any other actions I may want to perform when the checkbox is actually checked)?

Answer 1

try touchend and if it works for click as well use the following way , else separate it

$sortable.on("touchend click", 'input[type="checkbox"]', function(e) {
    if(e.type == 'touchend'){
        $(this).off('click');
        // your function
    }
});

else try this for both

let checked = false;
$sortable.on("touchend click", 'input[type="checkbox"]', function(e) {
   if(e.type == "touchend") {
    checked = true;
    // your function
  }
  else if(e.type == "click" && !checked ) {
    // your function
  }
});
READ ALSO
Upload a photo on click/submit button

Upload a photo on click/submit button

how can I get jQuery to execute on click instead of just when user chooses a file? I tried onclick and submit on line 2 instead of change, to no avail:

32
How to return a message or value after checking for file with similar hash in Google Drive using ASP.NET

How to return a message or value after checking for file with similar hash in Google Drive using ASP.NET

I am trying to compare the hash of the files that are in the Google Drive but I am unsure how to do itI have a compare hash code block:

26
Upload a file using ajax for PHP using: TypeError

Upload a file using ajax for PHP using: TypeError

I'm actually try to upload an image file by using jQuery ajax methodBut I still have two errors

45
Javascript is sorting part of the array

Javascript is sorting part of the array

I tried to find something about my problem but I haven't found anything yet

17