Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web

Web to Mobile, Simplifying UI Event Management

5.00/5 (2 votes)
2 Jan 2014CPOL2 min read 10.9K  
A very simple way to get the best user experience when moving from desktop browsers to mobile browsers.

Introduction

This article will look at a script I've developed to simplify improving the performance of websites when looked at through a mobile phone.

Background 

Recently whilst working on a new project, we all booted up our mobile phones and started testing. Immediately we all noticed that the amount of time required for the click event to fire through a touch on a mobile device was substantial and significantly reduced the usability of the application. Double taps came through as single clicks with the second tap being lost.

The reason this happens is because mobile phones support the touch based event architectures. Ontouchstart, ontouchend and ontouchmove are all new events which can be specified within you mark up and made use of on a mobile. When these events where added to the HTML to event started firing immediately.

The delay is because the phone's browser will look for a touch event all the way up to the window object before firing the click event. Hence the delay.

We investigated a number of ways to work around this.

The obvious way would be to specify both touch and click events. But we didn't want the repetition especially as we didn't need any of the benefits touch events bring such as multi-touch and gestures e.t.c.

We looked at using JS to navigate the DOM on load and reassign all click events to touch events. This approach does work as long as you don't modify the DOM after the reassignment without reassigning again. But I considered this a development risk that would cause problems moving forward.

 In the end we came up with the following script, which is cross browser and, which, assuming you simply want a click programmed website to work better on a phone, works like a dream!

Using the code 

The following is the code block, please see the comments to understand how it works.

It works on IE8+, Chrome, Safari Win & Mac, Firefox.

JavaScript
//This method returns true if the browser and device supports touch events
function touchDeviceTest() {
    try {
        document.createEvent("TouchEvent");
        return true;
    } catch (e) {
        return false;
    }
}
//A flag for if the touches have scrolled
var tchHasScrolled = false;
//The random number generated for this touch event
var tchRandomId = 0.0;
//The random number generated for the last touch event
var tchRandomLastId = 0.0;
//The temp y position for the current touch
var touchYTemp = 0;

//this is the document scroll event method
function onDocumentScroll(e) {
    tchHasScrolled = true;
}

//this is the document click event method
function onDocumentClick(e) {
    //If the touch down and touch up randoms are the different
    //Then good event so continue
    if (tchRandomId != tchRandomLastId) {
        //set last to current
        tchRandomLastId = tchRandomId;
        //if touch device
        if (touchDeviceTest()) {
            //if target not an anchor
            if (e.target.tagName != 'A') {
                //stop normal behaviour
                e.stopPropagation();
                e.preventDefault();
            }
        }
    }
}

//this is the document touch start method
function onDocumentTouchStart(e) {
    //set has scrolled to false
    tchHasScrolled = false;
    //asssign a new random id
    tchRandomId = new Date().getMilliseconds() + Math.random();
    //store the touch y point
    touchYTemp = e.touches[0].clientY;
}

//this is the document touch move method
function onDocumentTouchMove(e) {
    //if touch has moved more than 10px set scrolled flag to true
    var y = e.touches[0].clientY;
    if (y > touchYTemp + 10 || y < touchYTemp - 10) {
        tchHasScrolled = true;
    }
}

//this is the document touch end method
function onDocumentTouchEnd(e) {
    //if there is still a touch, manage the scrolling
    if (e.touches[0]) {
        var y = e.touches[0].clientY;
        if (y > touchYTemp + 10 || y < touchYTemp - 10) {
            tchHasScrolled = true;
        }
    }
    //if the document hasn't scrolled
    if (!tchHasScrolled) {
        //get the event target
        var target = e.target.parentNode;
        //if the target has a click event
        if (e.target.onclick) {
            //call click event
            e.target.onclick(e);
        } else {
            //else, loop through parent looking for click event
            while (target != null) {
                if (target.onclick) {
                    //call click event
                    target.onclick(e);
                    break;
                }
              
                target = target.parentNode;
            }
        }
    }
}

//assign the methods to the events
if (!document.addEventListener) {
    document.attachEvent('onclick', onDocumentClick);
    document.attachEvent('onscroll', onDocumentScroll);
    document.attachEvent('ontouchstart', onDocumentTouchStart);
    document.attachEvent('ontouchmove', onDocumentTouchMove);
    document.attachEvent('ontouchend', onDocumentTouchEnd);
} else {
    document.addEventListener('click', onDocumentClick, true);
    document.addEventListener('scroll', onDocumentScroll, true);
    document.addEventListener('touchstart', onDocumentTouchStart, true);
    document.addEventListener('touchmove', onDocumentTouchMove, true);
    document.addEventListener('touchend', onDocumentTouchEnd, true);
}  

Essentially we're using the touch events on the window and the event target within the args to intercept the touch event and where found, execute the click event.

Points of Interest

Whilst the execution of the the link within an Anchor tag is not defined as an onclick event. Calling e.preventDefault within the event propagation for the click event will stop the anchor from working. This is why I specifically added an exclusion for Anchors.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)