Fetching jQuery Autocomplete Matches via Ajax

By Rob Gravelle

WEBINAR:
On-Demand

Application Security Testing: An Integral Part of DevOps


Welcome to the third installment on the jQuery Autocomplete Widget. This series has explored how to set the Autocomplete's behavior and appearance by overriding its many exposed methods, events and extension points. In the Tame Unwieldy Lists with the jQuery Autocomplete Widget article we learned how to include the Autocomplete widget in your web pages with a remote datasource. Then, in the Modify jQuery Autocomplete Widget Response Data article, we customized the menu content and appearance using the response event and _renderItem extension point. Today, we'll be employing the source event to perform a search of complex data via an Ajax request.

A Server-side Search

Normally, you can set the source property to the URL of your server-side component, as long as it returns items the supported JSON formats:

  1. An array of strings: [ "Item 1", "Item 2" ]
  2. An array of objects with "label" and "value" properties: [ { label: "Item 1", value: "item1" }, ... ]

The Autocomplete adds a term field to the query string, which your server-side script can use to filter the results. For example, if the source option is set to "http://acme.com" and the user types "rob", a GET request would be made to http://acme.com?term=rob.

Having said that, there are cases where you may want to fetch the matches yourself. For those times, you can supply a function to the source property. Inside your function, you can fetch your items as well as perform extra processing on the client-side. When you're done, you would pass your data to the response() function for displaying. Here's an example that caches results in order to minimize server calls:

var cache = {};
$( "#autocomplete" ).autocomplete({
  minLength: 3,
  source: function( request, response ) {
    var term = request.term;
    if ( term in cache ) {
      response( cache[ term ] );
      return;
    }

    $.getJSON( "search.php", request, function( data, status, xhr ) {
      cache[ term ] = data;
      response( data );
    });
  }
});

A Client-side Search

If server-side languages such as C#, PHP, and Java aren't your strong suit, you can simply fetch the data via an Ajax call and then filter it on the client-side. While that could entail downloading a lot of data, it also affords you a lot of leeway as to how you format your data. Case in point, in the previous demos, we matched search terms against an array of restaurant names; our new demo will work with a longer datasource of countries, that we'll fetch via an Ajax call. The data is stored in a plaintext file in the following format:

AD:Andorra
AE:United Arab Emirates
AF:Afghanistan
AG:Antigua and Barbuda
AI:Anguilla
AL:Albania
AM:Armenia
AN:Netherlands Antilles
AO:Angola
AQ:Antarctica
AR:Argentina
AS:American Samoa
AT:Austria
AU:Australia
AW:Aruba
AX:\u00c5land Islands

Data Caching

In the first code snippet above, we saw an example of results caching. With such a long list of countries to download, it's even more important to cache the list so that we only have to fetch the data once. The ideal place to do that is the create() event. It's triggered when the autocomplete widget is instantiated via $('#autocomplete').autocomplete(). In the $.ajax success() function, we parse the data and format it for the autocomplete widget:

var aCountries = [],
    cache      = {};
$('#autocomplete').autocomplete({
    delay: 500,
    minLength: 3, 
    create: function( event, ui ) {
      $.ajax( {
        url: "https://codepen.io/blackjacques/pen/gvJVYo.html",
        dataType: "text",
        success: function( data ) {
          aCountries = data.split('\n').map(function(currentValue, index, arr) { 
            var labelValuePair = currentValue.split(':');
            return {
              label: labelValuePair[1],
              value: labelValuePair[0]
            }; 
          }); 
        }
      });
    }
});

The Search Code

By the time a search is performed, the country data has been loaded into the aCountries array. In addition, we can cache matches as well, so that lookups never have to be executed more than once per search term. Our search overrides the default behavior by anchoring the search term to the start of words. The autocomplete widget comes with its own escapeRegex() function to use terms within regexes. The results of Array.filter() are then stored in the cache and passed to the response() function:

source: function(request, response) { 
  var term = request.term.toLowerCase();
  if ( !(term in cache) ) {
    console.log('Storing in cache…');
    var matcher = new RegExp("\\b" + $.ui.autocomplete.escapeRegex(term), "i");
    cache[term] = aCountries.filter(function(country) {
      return matcher.test(country.label);
    });
    console.log(cache[term]);
  }
  response( cache[term] );
}

We can see the caching at work in the browser console:

The complete source code and working demo is up on Codepen for you to try. Here's a screenshot:

Conclusion

The versatility of the source attribute lends itself to a wide array of solutions for fetching and filtering search data. Depending on your particular strengths, you can either perform searches on the server or client. As we saw here today, the source attribute offers the opportunity to override the default search behavior as well as perform additional filtering, formatting, and caching.



Rob Gravelle

Rob Gravelle resides in Ottawa, Canada. His design company has built web applications for numerous businesses and government agencies. Email him.

Rob's alter-ego, "Blackjacques", is an accomplished guitar player, who has released several CDs and cover songs. His band, Ivory Knight, was rated as one of Canada's top hard rock and metal groups by Brave Words magazine (issue #92).



Make a Comment

Loading Comments...

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
  •  
  •  
  •  
Thanks for your registration, follow us on our social networks to keep up-to-date