jQuery calling click event after taphold event
cordova, jquery, jquery-mobile
Solution
Rather than use `tap` and `taphold` (which I've tried to use but ran into the same problems, it seems to be an inherent issue with the `taphold` event) you can use `vmousedown` and set a flag, then bind to `vmouseup` to determine if it was a `tap` or a `taphold`:
var tapTime = 0;
$('#my_item_'+items[idx].user_item_id).bind('vmousedown vmouseup', function (event) {
if (event.type == 'vmousedown') {
tapTime = new Date().getTime();
} else {
//event.type == 'vmouseup'
//here you can check how long the `tap` was to determine what do do
var duration = (new Date().getTime() - tapTime);
if (duration > 3000) {
//this is a tap-hold
ShowMyItemInfo(items[idx]);
} else {
//this is a tap
FitMyUpgradeItem(items[idx]);
}
}
});
For this to work properly you'll have to add an IIFE around the loop-code or change `ShowMyItemInfo(items[idx]);` to work without referencing the variable that changes each iteration of the loop. An easy to create an IIFE is to just use `$.each()`. Otherwise your loop would look something like this:
for(var idx in items)
{
(function (idx) {
...
})(idx);
}
IIFE = Immediately-Invoked-Function-Expression. It allows us to take a "snapshot" of the current state of variables we pass into the IIFE. So as we pass in `idx` (technically the second instance is the variable that's being passed in, and the first instance is the variable available inside the IIFE, which could be changed to something like `ids_new` for simplicity sake), the value passed in is saved for when the `tap` event handler fires.
Update
You can also set a timeout to determine `taphold` rather than using the `vmouseup` event:
//setup a timer and a flag variable
var tapTimer,
isTapHold = false;
$('#my_item_'+items[idx].user_item_id).bind('vmousedown vmouseup', function (event) {
if (event.type == 'vmousedown') {
//set the timer to run the `taphold` function in three seconds
//
tapTimer = setTimeout(function () {
isTapHold = true;
ShowMyItemInfo(items[idx]);
}, 3000);
} else {
//event.type == 'vmouseup'
//clear the timeout if it hasn't yet occured
clearTimeout(tapTimer);
//if the flag is set to false then this is a `tap` event
if (!isTapHold) {
//this is a tap, not a tap-hold
FitMyUpgradeItem(items[idx]);
}
//reset flag
isTapHold = false;
}
});
This way the event will fire after the user holds down their finger for three seconds. Then the `tap` event handler will only fire if that three seconds did not occur.
Problem
I'm developing a PhoneGap app for Android using Jquery and Jquery Mobile. I've got a list of items that need two events bound to each item in the list. I need a "taphold" event and a "click" event. The problem I'm having is when I do a "taphold", the correct "taphold" event is fired. However, as soon as I release, the click event is also fired. How can I prevent the click event from firing after a taphold? Code: ``` function LoadMyItems(items) { for(var idx in items) { var itemLine = '<div class="my_item" id="my_item_'+items[idx].user_item_id+'">' + '<img class="item_icon_32" src=./images/graphicFiles/Icon48/'+items[idx].item.graphic.graphicFiles.Icon48.filename+' />' + items[idx].item.name+ '</div>'; $('#my_list').append('<li>'+itemLine+'</li>'); $('#my_item_'+items[idx].user_item_id).bind('taphold', {userItem:items[idx]},ShowMyItemInfo); $('#my_item_'+items[idx].user_item_id).bind('click tap', {userItem:items[idx]},FitMyUpgradeItem); console.log('UserItem '+items[idx].user_item_id+' loaded and events bound'); } $('#my_items_loader').hide(); myScroll.refresh(); } ``` After the advice below, Here is what I ended up with. This works inside the iScroll object. ``` function LoadMyItems(items) { for(var idx in items) { var itemLine = '<div class="my_item" id="my_item_'+items[idx].user_item_id+'">' + '<img class="item_icon_32" src=./images/graphicFiles/Icon48/'+items[idx].item.graphic.graphicFiles.Icon48.filename+' />' + items[idx].item.name+ '</div>'; $('#my_list').append('<li>'+itemLine+'</li>'); (function(index) { var tapTime = 0; var xPos = 0; var yPos = 0; $('#my_item_'+items[index].user_item_id).bind('vmousedown vmouseup', function (event) { if (event.type == 'vmousedown') { tapTime = new Date().getTime(); xPos = event.pageX; yPos = event.pageY; var timer = setTimeout(function() { var duration = (new Date().getTime() - tapTime); var xDiff = Math.abs(mouseXPos - xPos); var yDiff = Math.abs(mouseYPos - yPos); if(duration >= 700 && (yDiff <= 40 || mouseXPos == 0)) ShowItemInfo(items[index].item); },750); } else { //event.type == 'vmouseup' var duration = (new Date().getTime() - tapTime); var xDiff = Math.abs(event.pageX - xPos); var yDiff = Math.abs(event.pageY - yPos); tapTime = new Date().getTime(); if (duration < 699 && yDiff <= 40) { //this is a tap FitMyUpgradeItem(items[index]); } } }); $('#my_item_'+items[index].user_item_id).bind('touchmove',function(event) { event.preventDefault(); }); })(idx); console.log('UserItem '+items[idx].user_item_id+' loaded and events bound'); } $('#my_items_loader').hide(); myScroll.refresh(); } ```