Skip to content

Instantly share code, notes, and snippets.

@ksafranski
Created August 9, 2012 21:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ksafranski/3308065 to your computer and use it in GitHub Desktop.
Save ksafranski/3308065 to your computer and use it in GitHub Desktop.
Simple jQuery Autocomplete plugin
/*
*
* Simple Autocomplete Plugin
* @author - Kent Safranski - http://www.fluidbyte.net
*
* HTML:
* --------------------------------------------------------------------
* <input class="autocomplete" data-src="path/to/processor.php" />
*
* CSS:
* --------------------------------------------------------------------
* .autocomplete-reveal { background: #f5f5f5; border: 1px solid #ccc; border-top: none; }
* .autocomplete-reveal li { padding: 3px 10px; cursor: pointer; }
* .autocomplete-reveal li:hover, .autocomplete-reveal li.selected { background: #dadced; }
*
* JAVASCRIPT:
* --------------------------------------------------------------------
*
* $('.autocomplete').autocomplete({ dataformat: "item.city+', '+item.state" });
*
*
* HOW IT WORKS - THE DATA:
* --------------------------------------------------------------------
* The concept is simple - the 'data-src' attribute on the input field
* is what tells the script where to grab the data. It works best with
* JSON in the JSend Format <http://labs.omniti.com/labs/jsend> :
*
* {
* "status":"success",
* "data":[
* {"city":"Little Rock","state":"AK"},
* {"city":"Denver","state":"CO"},
* {"city":"Baton Rouge","state":"LA"},
* ...
* ]
* }
*
* the 'dataformat' parameter represents the individual entity items so
* compare the JAVASCRIPT to the JSON and it's pretty simple to follow,
* where 'item' is the array returned.
*
*/
(function ($) {
$.fn.autocomplete = function (o) {
var o = jQuery.extend({
city: "item.city",
state: "item.state_prefix",
zip: "item.zip_code"
//dataformat: "item.city+', '+item.state_prefix"
}, o);
$(this)
.each(function () {
// Set the field
acfield = $(this);
// Get the data source
var acdatasrc = acfield.attr('data-src');
// Disable default autocomplete
acfield.attr('autocomplete', 'off');
// Wrap yo stuff!
acfield.wrap('<div class="autocomplete-wrapper" />');
acfield.parent('.autocomplete-wrapper')
.append('<ul class="autocomplete-reveal"></ul>');
// Just some definition
acchosen = null;
var acwrapper = $('.autocomplete-wrapper');
var acreveal = $('.autocomplete-reveal');
var acitem = $('.autocomplete-reveal li');
// Apply control styles
acwrapper.css({
'position': 'relative'
});
acreveal.css({
'display': 'none',
'position': 'absolute',
'margin': '0',
'padding': '0',
'width': $(this)
.outerWidth() - 2 + 'px',
'top': $(this)
.outerHeight() + 'px'
});
acitem.css({
'list-style': 'none'
});
// Process
acfield.on('keyup', function (e) {
if (e.which !== 40 && e.which !== 38) { // Not arrow keys, right?
if (acfield.val() != "") { // There's text in the field, right?
$.get(acdatasrc + '?ac=' + acfield.val(), function (data) {
// Clean slate
acreveal.html(''); // Clean drop-down
acchosen = null; // Reset and chosen selections
// Process response
var output = $.parseJSON(data);
// Success?
if (output.status == 'success') {
var list = output.data;
// No results
if (list.length == 0) {
acreveal.hide();
}
// Loop it out!
else {
$.each(list, function (i, item) {
acreveal.append('<li value="' + eval(o.zip) + '">' + eval(o.city) + ', ' + eval(o.state) + '</li>');
});
acreveal.show();
}
}
});
} else {
acreveal.hide(); // Nope, no text in the field...
}
}
});
// What do we do on enter or tab key?
acfield.on('keydown', function (e) { // 13-enter
if (e.keyCode == 13 || e.keyCode == 9) {
if (acchosen !== null) { // Something's been selected from the autocomplete
var acsuggest = acreveal.children('li.selected')
.text();
acfield.val(acsuggest);
acreveal.hide();
e.preventDefault();
//return false;
}
}
});
// Arrow key navigation? Why not!
acfield.on('keyup', function (e) { // 38-up, 40-down
if (e.keyCode == 40) {
if (acchosen === null) {
acchosen = 0;
} else if ((acchosen + 1) < $('li')
.length) {
acchosen++;
}
acreveal.children('li')
.removeClass('selected');
acreveal.children('li:eq(' + acchosen + ')')
.addClass('selected');
return false;
}
if (e.keyCode == 38) {
if (acchosen === "") {
acchosen = 0;
} else if (acchosen > 0) {
acchosen--;
}
acreveal.children('li')
.removeClass('selected');
acreveal.children('li:eq(' + acchosen + ')')
.addClass('selected');
return false;
}
});
// Hover over arrow-selected reveal
acreveal.on('hover', function () {
acreveal.children('li')
.removeClass('selected');
});
// Click on item
acreveal.on('click', 'li', function () {
acfield.val($(this)
.text());
acchosen = null;
});
// Hide on blur (pause for click)
acfield.on('blur', function () {
setTimeout(function () {
acreveal.hide();
}, 200);
acchosen = null;
});
});
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment