Displaying JQuery UI autocomplete as a table
Asked Answered
M

4

7

I am using JQuery UI's autocomplete. I have a number of values, as well as a small collection of keywords, one of which is assigned to each value. I would like to display each pair in a mini-table, with the keyword in one cell and the value in the other. To do this, I am overwriting _renderItem, as mentioned in the documentation. However, when I do this, clicking on a value (or a keyword) doesn't actually do anything, so I cannot select any values. I suspect it has something to do with data("item.autocomplete", item) not being in the right place. Or maybe I need to overwrite some other function higher up (_renderMenuor _suggest?)

$( "#tags" ).autocomplete({
source: getItems
})
.data( "autocomplete" )._renderItem = function( ul, item ) {
return $( '<table></table>' )
    .data( "item.autocomplete", item )
    .append( '<tr><td>' + item.keyword + '</td><td> ' + item.value + "</td></tr>" )
    .appendTo( ul );
};
Merridie answered 8/12, 2011 at 14:7 Comment(2)
I'm not sure, but autocomplete needs an li element inside the ul ?Plumbing
This is a very old question but I think the answer to this more recent question should be useful: https://mcmap.net/q/1076690/-jquery-ui-autocomplete-_renderitem-seems-to-interfere-with-select-event/422353Kaufmann
D
8

I think this can help you,here is the js:

$(function() {
//overriding jquery-ui.autocomplete .js functions
$.ui.autocomplete.prototype._renderMenu = function(ul, items) {
  var self = this;
  //table definitions
  ul.append("<table><thead><tr><th>ID#</th><th>Name</th><th>Cool&nbsp;Points</th></tr></thead><tbody></tbody></table>");
  $.each( items, function( index, item ) {
    self._renderItemData(ul, ul.find("table tbody"), item );
  });
};
$.ui.autocomplete.prototype._renderItemData = function(ul,table, item) {
  return this._renderItem( table, item ).data( "ui-autocomplete-item", item );
};
$.ui.autocomplete.prototype._renderItem = function(table, item) {
  return $( "<tr class='ui-menu-item' role='presentation'></tr>" )
    .data( "item.autocomplete", item )
    .append( "<td >"+item.id+"</td>"+"<td>"+item.value+"</td>"+"<td>"+item.cp+"</td>" )
    .appendTo( table );
};
//random json values
var projects = [
    {id:1,value:"Thomas",cp:134},
    {id:65,value:"Richard",cp:1743},
    {id:235,value:"Harold",cp:7342},
    {id:78,value:"Santa Maria",cp:787},
    {id:75,value:"Gunner",cp:788},
    {id:124,value:"Shad",cp:124},
    {id:1233,value:"Aziz",cp:3544},
    {id:244,value:"Buet",cp:7847}
];
$( "#project" ).autocomplete({
    minLength: 1,
    source: projects,
    //you can write for select too
    focus: function( event, ui ) {
        //console.log(ui.item.value);
        $( "#project" ).val( ui.item.value );
        $( "#project-id" ).val( ui.item.id );
        $( "#project-description" ).html( ui.item.cp );
        return false;
    }
})
});

You can check out this fiddle

Dystrophy answered 28/4, 2014 at 7:28 Comment(4)
Works but had to remove the class and role from "<tr class='ui-menu-item' role='presentation'></tr>" for the table to display properly. ThanksOmniumgatherum
Don't you end up with a <table> inside the <ul>? While it looks ok in your fiddle, that's probably not the best solution.Inch
Agreed, I just wanted to show a process. Surely there are other way of doing thisDystrophy
@MominAlAziz keyboard navigation ?Hardi
D
2

You cannot create a <table> in the _renderItem to render an item directly. The plugin uses a <ul> as the container for the menu items.

You have to stick to using <li> elements and are able only to customize the markup within the <li>, inserting your table element within it.

But I would personnaly not use a table to do that. Can't you simply use span elements ?

Dilatation answered 8/12, 2011 at 14:38 Comment(0)
P
2

Update: one day after i found a plugin 10000 times better for my project context. Select2, check the "loading remote data" example.

Original answer:

I upgraded the previous samples to use the current jQuery versions:

JS Fiddle example with jQuery 2.1.4 and jQuery UI 1.11.4

Also, i changed this autocomplete to use as a custom widget and included support for keyboard navigation.

Code:

$.widget('custom.tableAutocomplete', $.ui.autocomplete, {
options: {
    open: function (event, ui) {
        // Hack to prevent a 'menufocus' error when doing sequential searches using only the keyboard
        $('.ui-autocomplete .ui-menu-item:first').trigger('mouseover');
    },
    focus: function (event, ui) {
        event.preventDefault();
    }
},
_create: function () {
    this._super();
    // Using a table makes the autocomplete forget how to menu.
    // With this we can skip the header row and navigate again via keyboard.
    this.widget().menu("option", "items", ".ui-menu-item");
},
_renderMenu: function (ul, items) {
    var self = this;
    var $table = $('<table class="table-autocomplete">'),
        $thead = $('<thead>'),
        $headerRow = $('<tr>'),
        $tbody = $('<tbody>');

    $.each(self.options.columns, function (index, columnMapping) {
        $('<th>').text(columnMapping.title).appendTo($headerRow);
    });

    $thead.append($headerRow);
    $table.append($thead);
    $table.append($tbody);

    ul.html($table);

    $.each(items, function (index, item) {
        self._renderItemData(ul, ul.find("table tbody"), item);
    });
},
_renderItemData: function (ul, table, item) {
    return this._renderItem(table, item).data("ui-autocomplete-item", item);
},
_renderItem: function (table, item) {
    var self = this;
    var $tr = $('<tr class="ui-menu-item" role="presentation">');

    $.each(self.options.columns, function (index, columnMapping) {
        var cellContent = !item[columnMapping.field] ? '' : item[columnMapping.field];
        $('<td>').text(cellContent).appendTo($tr);
    });

    return $tr.appendTo(table);
}
});

$(function () {
var result_sample = [{
    "id": 26,
    "value": "Ladislau Santos Jr.",
    "email": "[email protected]",
    "address": "9867 Robert St"
}, {
    "id": 14,
    "value": "Pablo Santos",
    "email": "[email protected]",
    "address": "7540 Moreira Ponte"
}, {
    "id": 13,
    "value": "Souza, Nogueira e Santos",
    "email": null,
    "address": "3504 Melo Marginal"
}];

$('input#search_field').tableAutocomplete({
    source: result_sample,
    columns: [{
        field: 'value',
        title: 'Name'
    }, {
        field: 'email',
        title: 'E-mail'
    }, {
        field: 'address',
        title: 'Address'
    }],
    delay: 500,
    select: function (event, ui) {
        if (ui.item != undefined) {
            $(this).val(ui.item.value);
            $('#selected_id').val(ui.item.id);
        }
        return false;
    }
});
});
Prow answered 6/5, 2015 at 15:47 Comment(1)
There is a scroll issue while keyboard navigation when item overflows viewport or max-height. jsfiddle.net/aghilanbaskar/ed2hvg7x/1Plano
P
0

Nice example given in the Fiddle.

However after the latest versions upgrade of jQuery and jQuery UI that's just simply stopped working. Not absolutely, however jQuery UI now returning an error on menufocus, which is quite annoying.

JS Fiddle example with jQuery 2.1.3 and jQuery UI 1.11.3

$(function() {
//overriding jquery-ui.autocomplete .js functions
$.ui.autocomplete.prototype._renderMenu = function(ul, items) {
  var self = this;
  //table definitions
  ul.append("<table><thead><tr><th>ID#</th><th>Name</th><th>Cool&nbsp;Points</th></tr></thead><tbody></tbody></table>");
  $.each( items, function( index, item ) {
    self._renderItemData(ul, ul.find("table tbody"), item );
  });
};
$.ui.autocomplete.prototype._renderItemData = function(ul,table, item) {
  return this._renderItem( table, item ).data( "ui-autocomplete-item", item );
};
$.ui.autocomplete.prototype._renderItem = function(table, item) {
  return $( "<tr class='ui-menu-item' role='presentation'></tr>" )
    //.data( "item.autocomplete", item )
    .append( "<td >"+item.id+"</td>"+"<td>"+item.value+"</td>"+"<td>"+item.cp+"</td>" )
    .appendTo( table );
};
//random json values
var projects = [
	{id:1,value:"Thomas",cp:134},
    {id:65,value:"Richard",cp:1743},
    {id:235,value:"Harold",cp:7342},
    {id:78,value:"Santa Maria",cp:787},
	{id:75,value:"Gunner",cp:788},
	{id:124,value:"Shad",cp:124},
	{id:1233,value:"Aziz",cp:3544},
	{id:244,value:"Buet",cp:7847}
];
$( "#project" ).autocomplete({
	minLength: 1,
	source: projects,
    
	focus: function( event, ui ) {
        if (ui.item != undefined)
        {
            console.log(ui.item.value);
            $( "#project" ).val( ui.item.value );
		    $( "#project-id" ).val( ui.item.id );
		    $( "#project-description" ).html( ui.item.cp );
        }
		return false;
	}//you can write for select too
    /*select:*/
})
});
Parasynapsis answered 25/3, 2015 at 14:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.