JQuery raising click event after taphold event

I am developing a PhoneGap application for Android using jQuery and jQuery Mobile.

I have a list of items that need two events attached to each item in the list. I need a taphold event and a click event. The problem I am facing is when I do taphold, the corresponding taphold event occurs. However, as soon as I release, the click event will also fire. How can I prevent the click event from firing after clicking?

the 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(); } 

Following the advice below, this 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(); } 
+7
source share
4 answers

Instead of using tap and taphold (which I tried to use but faced with the same problems, this seems to be an inherent problem with the taphold event), you can use vmousedown and set the flag, then bind to vmouseup to determine if it was tap or 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 proper operation, you will need to add IIFE around the loop code or change ShowMyItemInfo(items[idx]); to work without a reference to a variable that changes each iteration of the loop. Easy to create IIFE - just use $.each() . Otherwise, your loop will look something like this:

 for(var idx in items) { (function (idx) { ... })(idx); } 

IIFE = Instantly call-function-expression. This allows us to take a “snapshot” of the current state of the variables that we pass to IIFE. Since we are going to idx (technically, the second instance is a variable that is passed inside, and the first instance is a variable available inside IIFE that can be changed to something like ids_new for simplicity), the value passed to is saved when it fires tap event handler.

Update

You can also set a timeout to define taphold instead of 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; } }); 

Thus, the event is triggered after the user holds his finger for three seconds. Then the tap event handler will fire only if these three seconds have not occurred.

+12
source

Just set this at the top of the document or anywhere before you determine the parity:

 $.event.special.tap.emitTapOnTaphold = false; 

Then you can use it as follows:

 $('#button').on('tap',function(){ console.log('tap!'); }).on('taphold',function(){ console.log('taphold!'); }); 
+5
source

Personally, I thought the answers here greatly complicated the problem. If you just need an easy way to continue using the taphold event and ignore the click event that fires when taphold is released, here is how I solved the same problem in my own project:

 // We will use this flag to ignore click events we don't want var skipNextClick = false; //Set up your event handler. You could do these using two handlers or one. I chose one. $('div.element').on('click taphold', function (e) { //set up a quick bool flag that is true if click var isClick = (e.type == 'click'); if (isClick && !skipNextClick) { //run your code for normal click events here... } else if (isClick && skipNextClick) { //this is where skipped click events will end up... //we need to reset our skipNextClick flag here, //this way, our next click will not be ignored skipNextClick = false; } else { //taphold event //to ignore the click event that fires when you release your taphold, //we set the skipNextClick flag to true here. skipNextClick = true; //run your code for taphold events here... } }); 
+1
source

Use tap \ vclick and click instead - the Tap event fires twice after clicking.

 $('#my_item_'+items[idx].user_item_id).bind('vclick', ... $('#my_item_'+items[idx].user_item_id).bind('taphold', ... 

In this example, the click is not actually called after taphold. Check it out here: http://jsfiddle.net/YL8hj/43/

Edit:

jQuery Mobile automatically binds a touch event to certain elements. when combining iScroll with jQuery Mobile it might be a good idea to link a separate function for the touchmove event and prevent the event from bubbling up (event.preventDefault ()). By doing this, jQuery Mobile will not be able to handle the touch event while users interact with the iScroll element.

also http://appcropolis.com/blog/jquery-wrapper-for-iscroll/ credit https://stackoverflow.com>.

0
source

All Articles