I am trying to make trigger based auto-complete in textarea using jQuery autocomplete. (when you type "#", the autocomplete starts).
Till now I am able to implement it for the case where the data is an array.
HTML
<textarea class="searchBox" rows="10" cols="20"></textarea>
jQuery
var triggered = false; // By default trigger is off
var trigger = "#"; // Defining the trigger
$(".searchBox").autocomplete({
source: [ // defining the source
"A",
"Apple",
"S",
"D",
"q"],
search: function () { // before search, if not triggerred, don't search
if (!triggered) {
return false;
}
},
select: function (event, ui) { // invokes the data source, search starts
var text = this.value;
var pos = text.lastIndexOf(trigger);
this.value = text.substring(0, pos + trigger.length) + ui.item.value;
triggered = false;
return false;
},
focus: function (event, ui) {
return false;
},
minLength: 0 // minimum length of 0 require to invoke search
});
$('.searchBox').keyup(function (e) {
if (e.keyCode == 38 || e.keyCode == 40) {
return;
}
var text = this.value;
var len = text.length;
var last;
var query;
var index;
if (triggered) {
index = text.lastIndexOf(trigger);
query = text.substring(index + trigger.length);
$(this).autocomplete("search", query);
} else if (len >= trigger.length) {
last = text.substring(len - trigger.length);
triggered = (last === trigger);
}
});
Here is its fiddle : http://jsfiddle.net/5x9ZR/4/
Now I was trying to implement it when the data is in the form of json object.
But the autocomplete isn't responding with results.
I tried it bare. ( without any trigger mechanism ). It isnt displaying any results.
Code:
HTML
<textarea class="searchBox" rows="10" cols="20"></textarea>
jQuery
var triggered = false; // By default trigger is off
var trigger = "#"; // Defining the trigger
var data = [{
"name": "needmoreinfo",
"email": "needmoreinfo"
}, {
"name": "explained",
"email": "explained"
}, {
"name": "raypipeline09",
"email": "raypipeline09"
}];
$(".searchBox").autocomplete({
source: data,
search: function () { // before search, if not triggred, don't search
if (!triggered) {
return false;
}
},
select: function (event, ui) { // invokes the data source, search starts
var text = this.value;
var pos = text.lastIndexOf(trigger);
this.value = text.substring(0, pos + trigger.length) + ui.item.email;
triggered = false;
return false;
},
focus: function () {
return false;
},
minLength: 0 // minimum length of 0 require to invoke search
})._renderItem = function (ul, item) {
return $("<li>")
.append("<a>" + item.name + "<br>" + item.email + "</a>")
.appendTo(ul);
};
$('.searchBox').keyup(function (e) {
if (e.keyCode == 38 || e.keyCode == 40) {
return;
}
var text = this.value;
var len = text.length;
var last;
var query;
var index;
if (triggered) {
index = text.lastIndexOf(trigger);
query = text.substring(index + trigger.length);
$(this).autocomplete("search", query);
} else if (len >= trigger.length) {
last = text.substring(len - trigger.length);
triggered = (last === trigger);
}
});
Here is the fiddle of what I tried. http://jsfiddle.net/HGxSX/
Where I am going wrong ? Please explain.
Solved it.
There is a bug in the jQuery due to which this was happening.
The data has to be in the form of "label" and "value". Otherwise it doesn't works.
Thanks to anyone who tried.
Here is the final working fiddle : http://jsbin.com/qakefini/7
PS: I tried making account on the jQuery website but could not login. Its saying some redirection problem. If someone has an account, please report the bug.
Doesnt seem to like json strings without a label - it uses this on its keyup to check values..
see your updated/destroyed fiddle:
http://jsfiddle.net/jFIT/HGxSX/1/
var data = [
{
value: "jquery",
label: "jQuery",
desc: "the write less, do more, JavaScript library",
icon: "jquery_32x32.png",
name: "needmoreinfo",
email: "needmoreinfo"
},{
and in your autocomplete function the renderitem was missing some things, you should update the version of jquery your using btw.. seems alot simpler in 1.9:
}).data( "autocomplete" )._renderItem = function( ul, item ) { console.log('wut');
return $( "<li>" )
.data( "item.autocomplete", item )
.append( "<a>" + item.email + "<br>" + item.name + "</a>" )
.appendTo( ul );
};
Related
I convert an application from Core 1.1 to 2.2. Now some of my JS is not working
After conversion I noticed that my columns were no longer sorting when I clicked on them. I added some JS code and now it works. This is when I found that there was a custom JS lib with the sorting code in there but it no longer worked.
I also found that the filtering (client side) is not working.
I converted the code following the instructions in https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/?view=aspnetcore-1.1
Here is the JS script to perform the filtering.
(function ($) {
$.fn.appgrid = function appgrid() {
function configureFilter() {
$("[data-update-departments]").on("change", function () {
var triggerControl = $(this);
var connectedControl = $(triggerControl.data("update-departments"));
if (!connectedControl.data("default")) {
connectedControl.data("default", connectedControl.children());
}
var triggerValue = triggerControl.find(":selected").val();
if (triggerValue) {
$.getJSON("/ManageNomination/GetDepartments?company=" + triggerValue, function (data) {
if (data) {
connectedControl.children().remove();
connectedControl.append('<option value=""></option>');
for (var i = 0; i < data.length; i++) {
connectedControl.append('<option value="' + data[i] + '">' + data[i] + '</option>');
}
connectedControl.removeAttr("disabled");
}
});
} else {
connectedControl.children().remove();
connectedControl.attr("disabled", "disabled");
}
})
$("#applyFilter").on("click", function () {
filter = $.extend({}, defaultFilter);
$("[id^=filter-]").each(function () {
var control = $(this);
var controlId = control.attr("id").substr(7);
if (this.type === "text" || this.type === "date") {
filter[controlId] = control.val();
} else if (this.type === "select-one") {
filter[controlId] = control.find(":selected").val();
}
});
localStorage.setItem('filter', JSON.stringify(filter));
refreshData();
$("#filter-applied-message").show();
});
$(".clearFilter").on("click", function () {
filter = $.extend({}, defaultFilter);
localStorage.removeItem('filter');
localStorage.removeItem('currentPage');
refreshData();
$("#filter-applied-message").hide();
setFilterControlValues();
});
setFilterControlValues();
}
function setFilterControlValues() {
// repopulate the filter fields with the saved filter values
$("[id^=filter-]").each(function () {
var control = $(this);
var controlId = control.attr("id").substr(7);
control.val(filter[controlId] || defaultFilter[controlId] || "");
if (this.type === "select-one" && control.data("update-departments")) {
if (control.find(":selected").val()) {
// control is a connected dropdown and has a selected value
$(control.data("update-departments")).removeAttr("disabled");
} else {
$(control.data("update-departments")).attr("disabled", "disabled");
}
}
// open the filter panel automatically
//$(".filterPanel").collapse("show");
});
}
So the dropdowns for the filtering are populated but when I select a value to filter on, nothing happens.
TIA
HaYen
In creating a table cells with very cool options I need to take two steps. First I create the table cell as a DOM object in javascript with all the 'normal' functionality, like is it a checkbox, a select, an input, a link, etc.
Then I need to put the table on the page to do the next step, which I consider advanced functionality like jqueryui's autocomplete and date select. It is awesome to have these drop downs for the user.
I do have this working, however, I do need to make two calls. The first to createTableCell, then I render, then I need to make another call to postRenderTableFunctions to get the autocomplete functionality working. So the question is, why the second call, what is it about jqueryui that will not work on the first call. You can see the commented section under input creation where I tried to get the autocomplete working.
function createTableCell(name, td_def)
{
var cell=document.createElement('td');
if(td_def['type'] == 'date')
{
var element = document.createElement('input');
element.name = name;
element.id = name;
cell.appendChild(element);
$('#' + element.id).datepicker(
{
dateFormat: 'yy-mm-dd',
onSelect: function ()
{
$(this).focus();
},
onClose: function (dateText, inst)
{
$(this).select();
}
});
}
else if(td_def['type'] == 'checkbox')
{
element = document.createElement('input');
element.type = 'checkbox';
element.name = name;
element.id = name;
/*if(this.tdo[r][td_def['db_field']]['data'] == 1)
{
element.checked = true;
}*/
cell.appendChild(element);
}
else if (td_def['type'] == 'select')
{
element = document.createElement('select');
element.name = name;
element.id = name;
var option = document.createElement('option');
option.value = 'NULL';
option.appendChild(document.createTextNode("Select..."));
element.appendChild(option);
for (var j in td_def['select_names'])
{
option = document.createElement('option');
option.value = td_def['select_values'][j];
option.appendChild(document.createTextNode(td_def['select_names'][j]));
element.appendChild(option);
}
cell.appendChild(element);
}
else if (td_def['type'] == 'tree_select')
{
element = document.createElement('select');
element.id = name;
element.name = name;
var option = document.createElement('option');
option.value = 'NULL';
option.appendChild(document.createTextNode("Select..."));
element.appendChild(option);
var level = 0;
//console.log(td_def['select_array']);
this.addNestedSelectOptions(element, td_def['select_array'], level);
if (typeof td_def['properties'] !== 'undefined')
{
for (var index in td_def['properties'])
{
eval('element.' + index + '= ' + td_def['properties'][index] + ';');
}
}
cell.appendChild(element);
}
else if (td_def['type'] == 'input')
{
element = document.createElement('input');
element.type = 'text';
element.id = name;
element.name = name;
cell.appendChild(element);
/*
if(typeof td_def['autoComplete'] != 'undefined')
{
console.log('attempting Autocomplete');
$( "#" + name ).autocomplete({
source: function( request, response )
{
$.ajax(
{
url: td_def['autoComplete']['url'],
type: 'GET',
async: true,
data:
{
ajax_request: td_def['autoComplete']['ajax_request'],
featureClass: "P",
style: "full",
maxRows: 12,
search_terms: request.term
},
success: function( data )
{
console.log(data);
parsed_autocomplete_data = parseJSONdata(data);
response( parsed_autocomplete_data);
}
});
},
search: function()
{
// custom minLength
var term = this.value;
//console.log(term);
if(typeof td_def['minLength'] != 'undefined')
{
var minL = td_def['minLength'];
}
else
{
var minL = 1;
}
if ( term.length < minL )
{
return false;
}
},
focus: function()
{
// prevent value inserted on focus
return false;
},
open: function(event, ui)
{
var dialog = $(this).closest('.ui-dialog');
if(dialog.length > 0){
$('.ui-autocomplete.ui-front').zIndex(dialog.zIndex()+1);
}
},
select: function( event, ui )
{
selected_autocomplete_index = $.inArray(ui.item.value, parsed_autocomplete_data);
}
});
}
*/
}
else if (td_def['type'] == 'textarea')
{
element = document.createElement('TEXTAREA');
element.id = name;
element.name = name;
cell.appendChild(element);
}
else if (td_def['type'] == 'td')
{
cell.innerHTML = 'TBD';
cell.name = name;
cell.id = name;
}
else
{
alert(td_def['type'] + ' have not coded that.....');
}
return cell;
function addNestedSelectOptions(element, category_array, level)
{
for (var key in category_array)
{
option = document.createElement('option');
option.value = key;
name = category_array[key]['name'];
for(i=0;i<level;i++)
{
name = "\u00A0" + name;
name = "\u00A0" + name;
}
option.appendChild(document.createTextNode(name));
element.appendChild(option);
if(!$.isEmptyObject(category_array[key]['children']))
{
addNestedSelectOptions(element, category_array[key]['children'], level+1);
}
}
}
}
//this function needs to be called separately.
function postRenderTableFunctions(table_div_id, table_def)
{
//extra jquery functionality -- needs to go after stuff is rendered
for(var i=0;i<table_def.length;i++)
{
if(typeof table_def[i]['autoComplete'] != 'undefined')
{
var id = table_div_id + '_' + table_def[i]['db_field'];
console.log(id);
//is the auto complete open?
/*$("#" + id ).bind('autocompleteopen', function(event, ui)
{
$(this).data('is_open',true);
});
$("#" + id ).bind('autocompleteclose', function(event, ui)
{
$(this).data('is_open',false);
});*/
/*$( "#" + id ).bind( "keydown", function( event )
{
//what is this for ?
if ( event.keyCode === $.ui.keyCode.TAB && $(this).data('is_open') )
{
event.preventDefault();
}
if ( event.keyCode === $.ui.keyCode.ENTER && !$(this).data('is_open'))
{
//do what?
}
});*/
var i2 = i;
var me = table_def;
$( "#" + id ).autocomplete({
source: function( request, response )
{
$.ajax(
{
url: me[i2]['autoComplete']['url'],
type: 'GET',
async: true,
data:
{
ajax_request: me[i2]['autoComplete']['ajax_request'],
featureClass: "P",
style: "full",
maxRows: 12,
search_terms: request.term
},
success: function( data )
{
console.log(data);
parsed_autocomplete_data = parseJSONdata(data);
response( parsed_autocomplete_data);
}
});
},
search: function()
{
// custom minLength
var term = this.value;
//console.log(term);
if(typeof table_def[i2]['minLength'] != 'undefined')
{
var minL = table_def[i2]['minLength'];
}
else
{
var minL = 1;
}
if ( term.length < minL )
{
return false;
}
},
focus: function()
{
// prevent value inserted on focus
return false;
},
open: function(event, ui)
{
var dialog = $(this).closest('.ui-dialog');
if(dialog.length > 0){
$('.ui-autocomplete.ui-front').zIndex(dialog.zIndex()+1);
}
},
select: function( event, ui )
{
selected_autocomplete_index = $.inArray(ui.item.value, parsed_autocomplete_data);
}
});
}
}
}
My original comment to your question -
I suspect i may work if you replace
$( "#" + name ).autocomplete({
with
$(element).autocomplete({
though I don't currently have means to test it.
My response -
Basically using $("#name") looks for an element with the ID name in the DOM. When you are running your code element has not been added to the DOM yet so the autocomplete cannot be attached to to your element.
Surrounding element with $() converts it to a jQuery variable which you can attach the autocomplete to before it is added to the DOM.
Using a jQuery filter example I found. Here is my live example. Here is the CodePen, (also the Fiddle if you don't like CodePen).
After typing something in the input, the boxes do realign and the numbers dissapear. However, when you delete the text you inputted, the numbers do not reappear unless you refresh the page. I tried messing around with the code below but wasn't having any luck. Thanks for you help!
$('#sortable').change(
function(){
if ($(this).val().length) {
$('#number').hide();
}
else {
$('#number').show();
}
});
Try this out:- http://jsfiddle.net/adiioo7/nYYBU/10/
JS:-
(function ($) {
jQuery.expr[':'].Contains = function (a, i, m) {
return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
};
function listFilter(header, list) {
var form = $("<form>").attr({
"class": "filterform",
"action": "#"
}),
input = $("<input>").attr({
"class": "filterinput",
"type": "text",
});
$(form).append(input).appendTo(header);
$(input).change(function () {
var list = $("#sortable");
var filter = $(this).val();
console.log(filter.length);
if (filter.length > 0) {
$(list).find("a:not(:Contains(" + filter + "))").parent().slideUp();
$(".number").hide();
$(".numberstwo").hide();
} else {
console.log($(".number"));
$(".number").show();
$(".numberstwo").show();
$(list).find("a").parent().slideDown();
}
return false;
}).keyup(function () {
$(this).change();
});
}
$(function () {
listFilter($("#header"), $("#sortable"));
});
}(jQuery));
Here's updated js...
Checkout Demo Fiddle
(function ($) {
jQuery.expr[':'].Contains = function (a, i, m) {
return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
};
function listFilter(header, list) {
var form = $("<form>").attr({
"class": "filterform",
"action": "#"
}),
input = $("<input>").attr({
"class": "filterinput",
"type": "text",
});
$(form).append(input).appendTo(header);
$(input).change(function () {
var filter = $(this).val();
if (filter) {
$(list).find("a:not(:Contains(" + filter + "))").parent().slideUp();
$(list).find("a:Contains(" + filter + ")").parent().slideDown();
} else {
$(list).find("li").slideDown();
}
return false;
}).keyup(function () {
$(this).change();
if ($(this).val().length) {
$('.number').hide();
} else {
$('.number').show();
}
});
}
$(function () {
listFilter($("#header"), $("#sortable"));
});
}(jQuery));
To check the entered text I normally use keyup.
Change is not triggered when the user types something but when he types and exits the box.
$('#sortable').blur(function(){
var len = $(this).val().length;
if (len) {
$('#number').hide();
}
else {
$('#number').show();
}
I tested the JQuery autocomplete UI widget and noticed that the autocomplete has extremely poor performance in IE when dealing with large amount of data. My client uses internet explorer 7.
I found a solution to mitigate the performance issue. Instead of returning all the matches of the autocomplete search I only return the first 40 matches. Code below
source: function (request, response) {
var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(request.term), "i");
var select_el = select.get(0); // get dom element
var rep = new Array(); // response array
var maxRepSize = 40; // maximum response size
// simple loop for the options
var looper = 0;
for (var i = 0; i < select_el.length; i++) {
var text = select_el.options[i].text;
if (!request || request == '') {
// add element to result array
rep[looper++] = {
label: text,
value: text,
option: select_el.options[i]
};
}
else if ( select_el.options[i].value && matcher.test(text) ) {
// add element to result array
rep[looper++] = {
label: text,
value: text,
option: select_el.options[i]
};
}
if ( rep.length > maxRepSize ) {
needMoreItems = true;
break;
}
}
// send response
response( rep );
},
The client asked me to append a "More Results" item to the autocomplete list. If there were more than 40 items that matched the search the "More Results" item would appear of at the bottom of the list. If a user clicked on the "More Results" item, the autocomplete drop down would expand to include the next 40 matches. I experimented with the jQuery autocomplete and I was able to populate the auto suggest list with the next 40 items but when the user clicked on one of the dynamically added items, I could not bind the click event to the Select Event of the autocomplete UI widget. Code below:
open: function( event, ui ) {
if (needMoreItems) {
needMoreItems = false;
$('<li class="ui-menu-item" role="menuitem" id="yoADDMORE" ><a class="ui-corner-all" tabindex="-1">... more available<br/><br/></a></li>')
.bind({
click: function(e) {
var appendHtml = '';
var select_el = select.get(0);
var maxRepSize = 40; // maximum response size
// simple loop for the options
var looper = 0;
for (var i = 41; i < select_el.length; i++) {
appendHtml += '<li class="ui-menu-item" role="menuitem"><a class="ui-corner-all" tabindex="-1">' + select_el.options[i].text + '</a></li>';
if ( looper ++ > maxRepSize ) {
needMoreItems = true;
break;
}
}
if (needMoreItems)
appendHtml += '<li class="ui-menu-item" role="menuitem" id="yoADDMORE" ><a class="ui-corner-all" tabindex="-1">... more available<br/><br/></a></li>';
$('#yoADDMORE').remove();
$('ul.ui-autocomplete').html($('ul.ui-autocomplete').html() + appendHtml);
$('ul.ui-autocomplete > li')
.bind({
mouseenter: function(e) {
// Hover event handler
$("> a",this).attr('class','ui-corner-all ui-state-hover');
},
mouseleave: function(e) {
// Hover event handler
$("> a",this).attr('class','ui-corner-all');
}
});
},
mouseenter: function(e) {
// Hover event handler
$("> a",this).attr('class','ui-corner-all ui-state-hover');
},
mouseleave: function(e) {
// Hover event handler
$("> a",this).attr('class','ui-corner-all');
}
})
.appendTo('ul.ui-autocomplete');
}
},
Links to jsFiddle
http://jsfiddle.net/eyecode/sX4Ba/
Any help would be appreciated.
Thanks in Advance
In order to list the top 20 options with a "More .." at the bottom of the first 20 items. Once a user presses "More .." link. All the items will be displayed in the drop down.
(function ($) {
$.widget("ui.typeaheadtextbox", {
_create: function () {
var self = this,
select = this.element.hide(),
theWidth = select.width(),
selected = select.children(":selected"),
value = selected.val() ? selected.text() : "";
var _searchItem = '';
var _more = false;
var _lastIndex = 0;
var _maxSize = 20;
var _rep = null;
var input = this.input = $("<input id='" + select[0].id + "_jq' style=\"width: " + theWidth + "px\">")
.insertAfter(select)
.val(value)
.autocomplete({
delay: 10,
minLength: 0,
source: function (request, response) {
var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(request.term), "i");
var j = 0;
_rep = response;
_searchItem = request.term;
var select_el = select.get(0); // get dom element
var rep = new Array(); // response array
for (var i = 0; i < select_el.length; i++) {
var text = select_el.options[i].text;
if (select_el.options[i].value && (!request.term || matcher.test(text))) {
j++;
if (j > _maxSize) {
_more = true;
_lastIndex = i;
break;
}
// add element to result array
rep[(j - 1)] = {
label: text.replace(new RegExp("^(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(_searchItem) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"), value: text, option: select_el.options[i]
};
}
}
return response(rep);
},
autoFocus:true,
open: function(event, ui) {
if (_more) {
_more = false;
$('<li class="ui-menu-item_more" role="menuitem" id="' + select.get(0).id + '_ADDMORE_' + _lastIndex + '" ><a class="ui-corner-all" tabindex="-1"><img width="16" src="Content/themes/base/images/icon-search-small.png"/> <strong>View All</strong></a></li>')
.bind({
click: function(e) {
var response = _rep;
var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(_searchItem), "i");
var select_el = select.get(0); // get dom element
var rep = new Array(); // response array
var j = 0;
for (var i = 0; i < select_el.length; i++) {
var text = select_el.options[i].text;
if (select_el.options[i].value && (!_searchItem || matcher.test(text))) {
// add element to result array
rep[j++] = {
label: text.replace(new RegExp("^(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(_searchItem) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"), value: text, option: select_el.options[i]
};
}
}
$(this).remove();
return _rep(rep);
},
mouseenter: function(e) { $("> a",this).attr('class','ui-corner-all ui-state-hover'); },
mouseleave: function(e) { $("> a",this).attr('class','ui-corner-all');}
})
.appendTo('ul.ui-autocomplete');
_lastIndex = 0;
return true;
}
},
select: function (event, ui) {
ui.item.option.selected = true;
self._trigger("selected", event, {
item: ui.item.option
});
},
change: function (event, ui) {
if (!ui.item) {
var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex($(this).val()) + "$", "i"),
valid = false;
select.children("option").each(function () {
if ($(this).text().match(matcher)) {
this.selected = valid = true;
return false;
}
});
if (!valid) {
// remove invalid value, as it didn't match anything
$(this).val("");
select.val("");
input.data("autocomplete").term = "";
return false;
}
}
}
})
.addClass("ui-widget ui-widget-content ui-corner-all");
input.data("autocomplete")._renderMenu = function( ul, items ) {
var self = this; var htm = ''; var beginHtm = '<li><a>'; var endHtm = '</a></li>';
for(var i=0;i<items.length;i++) {
htm += beginHtm + items[i].label + endHtm;
}
ul[0].innerHTML = htm;
var liTags = ul[0].getElementsByTagName('li');
for(var i=0;i<liTags.length;i++) {
$(liTags[i]).data("item.autocomplete", items[i]);
}
return true;
};
},
destroy: function () {
this.input.remove();
this.element.show();
$.Widget.prototype.destroy.call(this);
},
clear: function () {
this.element.val("");
this.input.val("");
}
});
})(jQuery);
Here is the code. IE7 spouts an "'active.0' is null or not an object" error on line 39, which is:
input.trigger("activate.autocomplete", [$.data(active[0], "originalObject")]); $("body").trigger("off.autocomplete");
Works perfectly in Firefox/Chrome/Opera. Any ideas? Many thanks and much appreciated.
/* jQuery Autocomplete
* Version 1.0
* Written by Yehuda Katz (wycats#gmail.com) and Rein Henrichs (reinh#reinh.com)
* #requires jQuery v1.2, jQuery dimensions plugin
*
* Copyright 2007 Yehuda Katz, Rein Henrichs
* Dual licensed under the MIT and GPL licenses:
* hxxp://www.opensource.org/licenses/mit-license.php
* hxxp://www.gnu.org/licenses/gpl.html
*
*/
/*
* #description Form autocomplete plugin using preloaded or Ajax JSON data source
*
* #example $('input#user-name').autocomplete({list: ["quentin", "adam", "admin"]})
* #desc Simple autocomplete with basic JSON data source
*
* #example $('input#user-name').autocomplete({ajax: "/usernames.js"})
* #desc Simple autocomplete with Ajax loaded JSON data source
*
*/
(function($) {
$.ui = $.ui || {}; $.ui.autocomplete = $.ui.autocomplete || {}; var active;
$.fn.autocompleteMode = function(container, input, size, opt) {
var original = input.val(); var selected = -1; var self = this;
$.data(document.body, "autocompleteMode", true);
$("body").one("cancel.autocomplete", function() {
input.trigger("cancel.autocomplete"); $("body").trigger("off.autocomplete"); input.val(original);
});
$("body").one("activate.autocomplete", function() {
input.trigger("activate.autocomplete", [$.data(active[0], "originalObject")]); $("body").trigger("off.autocomplete");
});
$("body").one("off.autocomplete", function(e, reset) {
container.remove();
$.data(document.body, "autocompleteMode", false);
input.unbind("keydown.autocomplete");
$("body").add(window).unbind("click.autocomplete").unbind("cancel.autocomplete").unbind("activate.autocomplete");
});
// If a click bubbles all the way up to the window, close the autocomplete
$(window).bind("click.autocomplete", function() { $("body").trigger("cancel.autocomplete"); });
var select = function() {
active = $("> *", container).removeClass("active").slice(selected, selected + 1).addClass("active");
input.trigger("itemSelected.autocomplete", [$.data(active[0], "originalObject")]);
input.val(opt.insertText($.data(active[0], "originalObject")));
};
container.mouseover(function(e) {
// If you hover over the container, but not its children, return
if(e.target == container[0]) return;
// Set the selected item to the item hovered over and make it active
selected = $("> *", container).index($(e.target).is('li') ? $(e.target)[0] : $(e.target).parents('li')[0]); select();
}).bind("click.autocomplete", function(e) {
$("body").trigger("activate.autocomplete"); $.data(document.body, "suppressKey", false);
});
input
.bind("keydown.autocomplete", function(e) {
if(e.which == 27) { $("body").trigger("cancel.autocomplete"); }
else if(e.which == 13) { $("body").trigger("activate.autocomplete"); }
else if(e.which == 40 || e.which == 9 || e.which == 38) {
switch(e.which) {
case 40:
case 9:
selected = selected >= size - 1 ? 0 : selected + 1; break;
case 38:
selected = selected <= 0 ? size - 1 : selected - 1; break;
default: break;
}
select();
} else { return true; }
$.data(document.body, "suppressKey", true);
});
};
$.fn.autocomplete = function(opt) {
opt = $.extend({}, {
timeout: 1000,
getList: function(input) { input.trigger("updateList", [opt.list]); },
template: function(str) { return "<li>" + opt.insertText(str) + "</li>"; },
insertText: function(str) { return str; },
match: function(typed) { return this.match(new RegExp(typed)); },
wrapper: "<ul class='jq-ui-autocomplete'></ul>"
}, opt);
if($.ui.autocomplete.ext) {
for(var ext in $.ui.autocomplete.ext) {
if(opt[ext]) {
opt = $.extend(opt, $.ui.autocomplete.ext[ext](opt));
delete opt[ext];
}
} }
return this.each(function() {
$(this)
.keypress(function(e) {
var typingTimeout = $.data(this, "typingTimeout");
if(typingTimeout) window.clearInterval(typingTimeout);
if($.data(document.body, "suppressKey"))
return $.data(document.body, "suppressKey", false);
else if($.data(document.body, "autocompleteMode") && e.charCode < 32 && e.keyCode != 8 && e.keyCode != 46) return false;
else {
$.data(this, "typingTimeout", window.setTimeout(function() {
$(e.target).trigger("autocomplete");
}, opt.timeout));
}
})
.bind("autocomplete", function() {
var self = $(this);
self.one("updateList", function(e, list) {
list = $(list)
.filter(function() { return opt.match.call(this.toLowerCase(), self.val()); })
.map(function() {
var node = $(opt.template(this))[0];
$.data(node, "originalObject", this);
return node;
});
$("body").trigger("off.autocomplete");
if(!list.length) return false;
var container = list.wrapAll(opt.wrapper).parents(":last").children();
var offset = self.offset();
opt.container = container
.css({top: offset.top + self.outerHeight(), left: offset.left, width: self.width()})
.appendTo("body");
$("body").autocompleteMode(container, self, list.length, opt);
});
opt.getList(self);
});
});
};
})(jQuery);
Check out:
http://github.com/istruble/jquery-autocomplete/commit/bdc926bd2c18c3ebab4e31463a8ae899fd761316#diff-1
It is a version of jquery.ui.autocomplete.js with most of the IE 7 issues fixed. I found a few more issues which I listed at the bottom along with how to fix them.
Here is my code that works javascript first:
$(".student_search").autocomplete("student_search.php", {
minChars: 2,
cacheLength: 20,
matchContains: true,
highlightItem: true,
parse: function(data) {
return $.map(eval(data), function(row) {
return {
data: row,
value: row.studentname, //value being searched for
result: row.studentidnumber //value in text input
}
});
},
formatItem: function(row, i, max, term) {
return "<span style='font-size: 110%;'>" + row.studentname + "</span><br/>" + "ID: " + row.studentidnumber + ", " + " Grade: " + row.studentgradenumber;
},
formatResult: function(row, i, max){
return row.studentidnumber;
}
});
});
Here is the code in the PHP file. It prints a JSON object with the data.
if(isset($_GET['q'])){
require_once("php/mysql.connect.php");
$request = strtolower($_GET['q']);
$query = mysql_query("SELECT
CONCAT(studentfname, ' ', studentlname, '')
AS studentname, studentidnumber,
CONCAT(studentgradenumber, 'th')
AS studentgradenumber
FROM studentinfo
WHERE studentlname LIKE '%".$request."%'
OR studentfname LIKE '%".$request."%'
OR studentidnumber LIKE '%".$request."%'") or die(mysql_error());
$results = array();
$i = 0;
while($row = mysql_fetch_assoc($query)) //fetch each result using the column name as the array key
{
foreach($row as $column=>$val) //loop through each column
{
$results[$i][$column] = $val; //build array using incremental row # and column name
}
$i++; //increase the row counter
}
print json_encode($results);
}
The JSON object that is printed is:
[{"studentname":"Joe Schmo","studentidnumber":"123456","studentgradenumber":"11th"}]
so row.studentname returns Joe Schmo. Where row is the name of the variable in the function and studentname is the name of the key from the JSON object.
Cheers!
I had problems with autocompletion of jquery ui version 1.8.9 and IE7. I use 1.8.16 now and it works.