Category Archives: jQuery

Modernizr: Detecting Touch Devices vs Non Touch Devices

Modernizr has a great feature that allows us to detect whether the browser is running on a touch device (iPad, smartphones, etc) or on a non-touch device (laptop, computer, etc).

Even though most modern touch devices support “proximity” hovering (navigating without touching the device screen), the browsing experience still suffer when dealing with onmouseover and onmouseout events.

So, let’s assume we want to implement WordPress’ Posts table. When we hover over any table row on a non-touch device, it will show additional actions such as “Edit”, “Quick Edit”, “Trash” and “View”. When we view the same page on a touch device, it will show the action without the hovering option.

The table may look something like this:-

<table class="table-actionable">
    <tr>
        <th>Artist</th>
        <th>Song Title</th>
    </tr>
    <tr>
        <td>System Of a Down</td>
        <td>Toxicity
            <ul class="hidden-action hide">
                <li><a href="/epic-app/buy/1">Buy</a></li>
                <li><a href="/epic-app/sell/1">Sell</a></li>
                <li><a href="/epic-app/trash/1">Trash</a></li>
            </ul>
        </td>
    </tr>
    <tr>
        <td>Eminem</td>
        <td>Rap God
            <ul class="hidden-action hide">
                <li><a href="/epic-app/buy/2">Buy</a></li>
                <li><a href="/epic-app/sell/2">Sell</a></li>
                <li><a href="/epic-app/trash/2">Trash</a></li>
            </ul>
        </td>
    </tr>
</table>

With Modernizr, we can now write something like this:-

<script>
    // On non-touch devices, show action list on mouse over and hide it on mouse out.
    if ( !Modernizr.touch ) {
        $( '.table-actionable tr' )
                .mouseover( function () {
                                $( this ).find( '.hidden-action' ).removeClass( 'hide' );
                            } )
                .mouseout( function () {
                               $( this ).find( '.hidden-action' ).addClass( 'hide' );
                           } );
    }
    // On touch devices, always show action list.
    else {
        $( '.hidden-action' ).removeClass( 'hide' );
    }
</script>

Shitty epic…

Managing the Order of AJAX Calls on Input Field’s Keyup Event

SCENARIO

Consider the following code:-

$('#employeeSearchField').keyup(function() {
	var query = $(this).val();

	$.get('/employees/api/search', { q: query }, function(data) {
		// do stuff
		...
	});

}).trigger('keyup');

When user types an employee’s name, “Mike”, in the search field, a web service call is fired per character typed. In this example, the following web service calls are made:-

  • GET /employees/api/search?q=M
  • GET /employees/api/search?q=Mi
  • GET /employees/api/search?q=Mik
  • GET /employees/api/search?q=Mike

Let’s assume this web service searches the input string against databases (or flat files, Facebook API, etc) and returns a list of employee JSON objects where their names match the given input string. The code above will take the result and display the employee list on the view.

PROBLEM

Since we can’t control how long each web service call takes to process the request, the order of the returned JSON objects might not match the order of the web service calls. As a result, we may have stale information being presented on the view. Further, we may have the annoying “flicker” problem where the old employee list overrides the new employee list on the view.

SOLUTION

To ensure the order of the returned JSON objects matches the order of the web service calls, we need to keep track each AJAX call’s timestamp. In this example, I’m using Moment.js, a date library, but you can also use the built-in Date object. For now, think of Moment.js as a Swiss Army Knife for date, or a Rambo Knife for date, or a MacGyver Knife for date… okay, maybe not MacGyver Knife since MacGyver can use a tooth pick to solve the date problem.

// keep track latest AJAX call's timestamp
var latestAjaxCallDateTime;

$('#employeeSearchField').keyup(function() {
	var query = $(this).val();

	// before executing the AJAX call, store the latest timestamp
	latestAjaxCallDateTime = moment();
	
	// set the "soon-to-be-executed" AJAX call's timestamp to be the same 
	// as the latest timestamp
	var currentAjaxCallDateTime = latestAjaxCallDateTime;

	$.get('/employees/api/search', { q: query }, function(data) {

		// if current timestamp is older than the latest timestamp, then 
		// omit the request 
		if (currentAjaxCallDateTime.isBefore(latestAjaxCallDateTime)) {
			return;
		}

		// do stuff
		...
	});

}).trigger('keyup');

Yes, this looks pretty hacky, but it works. The whole idea is we will not process the result if it is old. The key of making this whole thing work is to set latestAjaxCallDateTime as a global variable and set currentAjaxCallDateTime as a global variable WITHIN the anonymous function of the input field’s keyup event.