I just found out that the jQueryUI now has it\'s own built-in auto-complete combo box. Great news!
Unfortunately, the next thing I found is that making it multi-colu
you could also extend the AutoComplete widget and create a custom one, very similarly to what you're doing. Below is sample of how to show a flyout panel with 3 columns using a table and 3 unordered lists:
$.widget("custom.threecolumnautocomplete", $.ui.autocomplete, {
//going to extend the AutoComplete widget by customizing renderMenu and renderItems
_renderMenu: function (ul, items) {
var self = this;
//we'll define a table structure with 3 columns, and use UL elements to shove items into.
ul.append("<table class='customautocomplete' cellpadding='5'>\
<thead><tr>\
<th>Products</th>\
<th class='border'>Accessories</th>\
<th class='border'>Categories</th>\
</tr></thead>\
<tbody><tr>\
<td><ul class='products'></ul></td>\
<td class='border'><ul class='accessories'></ul></td>\
<td class='border'><ul class='categories'></ul></td>\
</tr></tbody>\
</table>");
$.each(items, function (index, item) {
self._renderItem(ul.find("table tbody"), item);
});
},
_renderItem: function (table, item) {
if (item.category.toLowerCase() == "product") {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a href='ProductDetails.aspx?Id=" + item.value + "'>" + item.label + "</a>") // need the actual URL for a product details page
.appendTo(table.find("ul.products"));
}
if (item.category.toLowerCase() == "accessory") {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a href='ProductDetails.aspx?Id=" + item.value + "'>" + item.label + "</a>") // need the actual URL for a product details page
.appendTo(table.find("ul.accessories"));
}
if (item.category.toLowerCase() == "category") {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a href='ProductSearch.aspx?q=" + item.value + "'>" + item.label + "</a>") // need the actual URL for a product search page
.appendTo(table.find("ul.categories"));
}
// default if a category was not matched, just append a row to the containing table
return $("<tr></tr>")
.data("item.autocomplete", item)
.append("<td colspan='3'>" + item.label + "</td>")
.appendTo(table);
}
});
$(function () {
$("#tbSearchBox").threecolumnautocomplete({
.
.
.
Thanks Lance for putting me on the right track. This answer is selectable and works in jquery-ui-1.11.4.
$.ui.autocomplete.prototype._renderMenu = function (ul, items) {
var self = this;
ul.append("<li class='ui-autocomplete-category' aria-label='header'><div class='listFullName listHeader'>Name</div><div class='listEmployeeID listHeader'>Employee ID</div><div class='listJobTitle listHeader'>Job Title</div></li>");
$.each(items, function (index, item) {
self._renderItemData(ul, item);
});
};
$.ui.autocomplete.prototype._renderItem = function (table, item) {
return $("<li>")
.data("item.autocomplete", item)
.append("<div class='listFullName'>" + item.label + "</div>" + "<div class='listEmployeeID'>" + item.value + "</div>" + "<div class='listJobTitle'>" + item.JobTitle + "</div>")
.appendTo(table);
};
$("#employeeLookup").autocomplete({
source: [
{ value: 1, label: "Bob Smith", JobTitle: "President" },
{ value: 2, label: "Bob Washington", JobTitle: "Vice-President" },
{ value: 3, label: "Bobby Fischer", JobTitle: "Secretary" },
{ value: 4, label: "Bobby Brady", JobTitle: "Treasurer" },
{ value: 5, label: "Bobby Socks", JobTitle: "Senior Vice-President" },
{ value: 6, label: "Barney Rubble", JobTitle: "Sidekick" },
{ value: 7, label: "Brenda Stevens", JobTitle: "Assistant Senior Vice-President" }
],
minLength:1
});
Here's the CSS I then add to format the columns:
.listFullName{
width:200px;
display:inline-block;
}
.listJobTitle{
width:150px;
display:inline-block;
}
.listEmployeeID{
width:100px;
display:inline-block;
}
Note that I add the 'ui-autocomplete-category' class to the header row to prevent it from being selectable in the results. I add the aria-label attribute to avoid a jQueryUI runtime exception apparently caused by encountering a list item that wasn't rendered using _renderItemData, although I did not do a deep dive into that.
Now, if you are pulling data via ajax, such as in the following example:
$("#employeeLookup").autocomplete({
source: function (request, response) {
// var id = $(this);
// alert(id);
$.ajax({
url: "Search.asmx/FindEmployee",
data: "{ 'partialName': '" + request.term + "'}",
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
dataFilter: function (data) { return data; },
success: function (data) {
response($.map(data.d, function (item) {
return {
FullName: item.FullName,
EmployeeID: item.Person_ID,
JobTitle: item.JobTitle,
label: item.FullName,
value:item.FullName
}
}))
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest);
}
});
},
minLength: 3,
delay: 500,
select: function (event, ui) {
alert("select" + ui.item.FullName);
}
});
You could change the _renderItem override to this:
$.ui.autocomplete.prototype._renderItem = function (table, item) {
return $("<li>")
.data("item.autocomplete", item)
.append("<div class='listFullName'>" + item.FullName + "</div>" + "<div class='listEmployeeID'>" + item.EmployeeID + "</div>" + "<div class='listJobTitle'>" + item.JobTitle + "</div>")
.appendTo(table);
};
In the Success event, jQueryUI is looking for "label" and "value" elements in the resulting array. You can map other elements as well for your own coding clarity, but "label" is the array element that jQueryUI Autocomplete will search/filter by, and "value" is the array element that JQueryUI Autocomplete will put into the html input once you select a value from the list.
I know this is an old thread but this widget supports multi column autocomplete
Here is a demo page using multi column autocomplete
The code below shows how to create a multi column autocomplete input:
$('input#starttime').menuoptions({
"Data": $("body").data("alltimes"),
"ClearBtn": true,
"onSelect": function(e, data) {
ResetEndTimeData(data.newVal);
},
"ColumnCount": 4,
"Width": 300,
"Height": 200,
"Sort": []
});
I ended up manually overriding the _renderMenu and _renderItem functions after all. Works like a charm so far, and was actually very easy to do. I was hoping for a "per-instance" solution, but we'll burn that bridge when we come to it. Here's what it came to, and thanks again!
$.ui.autocomplete.prototype._renderMenu = function(ul, items) {
var self = this;
ul.append("<table><thead><tr><th>ID#</th><th>Name</th><th>Cool Points</th></tr></thead><tbody></tbody></table>");
$.each( items, function( index, item ) {
self._renderItem( ul.find("table tbody"), item );
});
};
$.ui.autocomplete.prototype._renderItem = function(table, item) {
return $( "<tr></tr>" )
.data( "item.autocomplete", item )
.append( "<td>"+item.id+"</td>"+"<td>"+item.value+"</td>"+"<td>"+item.cp+"</td>" )
.appendTo( table );
};
$("#search").autocomplete({
source: [
{id:1,value:"Thomas",cp:134},
{id:65,value:"Richard",cp:1743},
{id:235,value:"Harold",cp:7342},
{id:982,value:"Nina",cp:21843},
{id:724,value:"Pinta",cp:35},
{id:78,value:"Santa Maria",cp:787}],
minLength: 1
});
I managed to get the full menu functionality working with a table layout, including selection, highlighting etc. I found that it is impossible to use <table><tr><td>
with autocomplete but you can put <div>
inside the autocomplete items and use display: table-cell
in CSS. This works from IE8 onwards and all the main modern browsers.
$.widget("custom.threecolumnautocomplete", $.ui.autocomplete,
{
_renderMenu: function( ul, items )
{
ul.addClass("threecolumnautocomplete");
return this._super(ul, items);
},
_renderItem: function (ul, item)
{
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a><div class='col'>" + item.id + "</div><div class='col'>" + item.value + "</div><div class='col'>" + item.cp + "</div></a>")
.appendTo(ul);
}
});
And then define CSS like this:
.threecolumnautocomplete li { display: table-row-group; }
.threecolumnautocomplete a { display: table-row !important; }
.threecolumnautocomplete .col { display: table-cell; }
.ie7 .threecolumnautocomplete .col { display: block; float: left; width: 15em; overflow: hidden; white-space: nowrap; }
This also shows a basic override with fixed width columns that works in IE7. To use this add the ie7
class higher up the document, e.g. on the body
element.
The post you reference is using a callback for the source instead of a url. The important part of it is the success callback on the ajax function. It takes response from the server and maps it to an object that the autocomplete expects to recieve:{label: '', value: ''}
. In that example they are setting the label (which shows in the menu) to the html they want displayed.
If you look at the autocomplete source the actual rendering of each item is handled by _renderItem, each label is wrapped by an <a>
and then appended to an <li>
element.
If what you want to do cannot be handled by setting the item label to whatever html you want to display, you could try and monkeypatch as described here.
Post some of your code and I might be able to help with a more concrete example.