Posts Tagged Javascript

Use tap events instead of click events in iPhone browser

When working on a web app for embedding in a iPhone application we came across jQTouch, a really nifty little jQuery plugin which makes it easy to create a web application UI that really resembles that of a native iPhone application.

We soon encountered a problem due to the fact that click events are rather slow to fire on the iPhone. There is a delay due to the fact that the iPhone waits for the user to complete a gesture before deciding that the intended gesture was in fact a click.

JQTouch uses divs to navigate between screens, so for example if you have the div

<div id="primary-view"></div>

you can simply navigate to it through a normal anchor link, and the transition will thanks to jQTouch be really “iPhone like”.

<a href="#primary-view">Primary view</a>

Our main problem is that we load our content dynamically through Ajax. So our links looked like this:

<a onclick="fetchContent();" href="#primary-view">Primary view</a>

This resulted in a race condition. The anchor link listens to the tap event which is fired much earlier than the click event, and therefore we mostly ended up in empty views. So we needed to replace all onclicks to ontap listeners. The problem then is that we could no longer test our webapp in a normal desktop based Safari browser.

So, we decided to happily go along and write inline onclick events on our links and other interaction elements. But while in the iPhone we see to it that the onClicks are removed and replaced with tap listeners.

That function looks like this:

function rebindClicks(){
    var userAgent = navigator.userAgent.toLowerCase();
    var isIphone = (userAgent.indexOf('iphone') != -1) ? true : false;
 
    if (isIphone) {
        // For each event with an inline onclick
        $('[onclick]').each(function() {
            var onclick = $(this).attr('onclick');
            $(this).removeAttr('onclick'); // Remove the onclick attribute
            $(this).bind("click", preventClickEvent); // See to it that clicks never happen
            $(this).bind('tap', onclick); // Point taps to the onclick
        });
    }
}
 
function preventClickEvent(event)  {
    event.preventDefault();
}

We now call this little function everytime the DOM is changed. If something turns up with an inline onclick. It is will be rerouted by jQuery to a tap listener instead.

Again, we felt we needed to do this because many of our developers do not have a Mac (and hence do not have the iPhone simulator). And testing on the iPhone can be really time consuming. So for testing during development we wanted to use onClick, and when testing on iPhone we wanted to use taps instead.

But the biggest bonus was without a doubt that things are overall much faster in the web application. Taps fire much faster than clicks in the iPhone.

Here’s how it looks running the same app both in desktop safari and embedded into the iPhone simulator.

, ,

4 Comments