MacMac MacMac - 7 months ago 33
Javascript Question

Stop the touchstart performing too quick when scrolling

I'm trying to figure out how to solve the tapped class being assigned to the elements when scrolling, but it's taking effect too quick which I need to delay it a bit when it's actually touched instead of touched while scrolling, this is my code of how it works:

$('div, a, span').filter('[tappable][data-tappable-role]').bind('touchstart', function()
{
var self = $(this);

self.addClass(self.data('tappable-role'));
}).bind('touchend', function()
{
var self = $(this);
self.removeClass(self.data('tappable-role'));
}).bind('click', function()
{
var self = $(this),
goTo = self.data('goto');

if(typeof goTo !== 'undefined')
{
window.location = goTo;
}
});


When scrolling, it will assign the class to the element when I've barely touched it, I want to prevent this from happening unless it's properly touched (not clicked). Although I tried experimenting with the setTimeout, but that doesn't work well as it delays but it will still assign the class later on.

This is how I did it with the setTimeout:

var currentTapped;
$('div, a, span').filter('[tappable][data-tappable-role]').bind('touchstart', function()
{
clearTimeout(currentTapped);

var self = $(this);

var currentTapped = setTimeout(function()
{
self.addClass(self.data('tappable-role'));
}, 60);
}).bind('touchend', function()
{
clearTimeout(currentTapped);

var self = $(this);
self.removeClass(self.data('tappable-role'));
}).bind('click', function()
{
clearTimeout(currentTapped);

var self = $(this),
goTo = self.data('goto');

if(typeof goTo !== 'undefined')
{
window.location = goTo;
}
});


How can I do this the effective way?



You need to view it on your iPhone/iPod/iPad or an emulator to test the fiddle.

UPDATE:

function nextEvent()
{
$(this).on('touchend', function(e)
{
var self = $(this);

self.addClass(self.data('tappable-role')).off('touchend');
})
.on('touchmove', function(e)
{
var self = $(this);

self.removeClass(self.data('tappable-role')).off('touchend');
})
.click(function()
{
var self = $(this),
goTo = self.data('goto');

if(typeof goTo !== 'undefined')
{
window.location = goTo;
}
});
}

$('div, a, span').filter('[tappable][data-tappable-role]').on('touchstart', this, nextEvent);

Answer

Here's how I did it:

Essentially, when you navigate a page you're going to tap or scroll. (Well there are other things like pinch and slide put you can figure them out later)...

So on a tap your 'touchstart' will be followed by a 'touchend' On a scroll your 'touchstart' will be followed by a 'touchmove'

Using Jq 1.7... on other versions you can use .bind()

function nextEvent() {
    //behaviour for end
    $(this).on('touchend', function(e){
        /* DO STUFF */
        $(this).off('touchend');
    });
    //behaviour for move
    $(this).on('touchmove', function(e){
        $(this).off('touchend');
    });     
}

$('div, a, span').filter('[tappable][data-tappable-role]').on('touchstart', this, nextEvent);

Basically, when a 'touchstart' happens, I bind actions to 'touchend' and 'touchmove'.

'Touchend' does whatever I would want a tap to do and then unbinds itself 'Touchmove' basically does nothing except unbind 'touchend'

This way if you tap you get action, if you scroll nothing happens but scrolling..

RESPONSE TO COMMENT: If I understand your comment properly, try this:

function nextEvent() {
    var self = $(this);
    self.addClass(self.data('tappable-role'))
    //behaviour for move
    $(this).on('touchmove', function(e){
         self.removeClass(self.data('tappable-role'));
    });     
}

$('div, a, span').filter('[tappable][data-tappable-role]').on('touchstart', this, nextEvent);