Departamento B Departamento B - 25 days ago 9
Javascript Question

Kendo AutoComplete - keyboard navigation doesn't work anymore after custom rows

In order to display more data than just the product name alone I've changed the rendering of the AutoComplete control. The control renders exactly like intended, but when I use the arrow keys to navigate to a row it will not select a row by itself.

However, when hover over a row first and then start using the arrow keys it works just like it used to work and I can use enter so select. Only the highlighting is lacking.

I would like to achieve the following:


  • To get arrow down working straight after typing instead of having to hover over the rows first

  • To get the selected row to have a different style (like background color) so the user sees which row is selected



I have tried to intercept what AutoComplete does in terms of setting a class or style to the selected row but I wasn't successful in getting it to show what it does to the row as it will hide the moment I go into Firebug and other tools that achieve the same.

I also can't figure out why the first arrow down doesn't work. I assume the control can't find a row anymore now the layout got more complex by introducing the table with a head, but I'm not sure.

function CreateAutocompletes() {
$('[data-autocomplete]').each(function (index, element) {
var requestUrl = $(element).attr('data-action');
var elm = $(element).autocomplete({
minLength: 2,
source: function(request, response) {
var warehouseId = $('#WarehouseId').val();
$.ajax({
url: requestUrl,
dataType: 'json',
data: {
query: request.term,
warehouseId: warehouseId
},
success: function(data) {
response($.map(data, function(item) {
return {
value: item.Name,
realValue: item.ProductId,
label: item.Name,
ProductId: item.ProductId,
SKU: item.SKU,
Name: item.Name,
Stock: item.Stock,
Ordered: item.Ordered,
BulkOrdered: item.BulkOrdered,
Underway: item.Underway,
Surplus: item.Surplus
};
}));
}
});
},
select: function(event, ui) {
var hiddenFieldName = $(this).attr('data-value-name');
$('#' + hiddenFieldName).val(ui.item.ProductId);
$(this).parent().next().children().first().focus();
}
}).data("ui-autocomplete");

elm._renderItem = function (table, item) {
return $("<tr class='ui-menu-item'></tr>")
.append("<td><a>" + item.SKU + "</a></td><td><a>" + item.Name + "</a></td>" +
"<td><a>" + item.Stock + "</a></td><td><a>" + item.Ordered + "</a></td><td><a>" + item.BulkOrdered + "</a></td>" +
"<td><a>" + item.Underway + "</a></td>")
.appendTo(table);
};

elm._renderMenu = function(ul, items) {
var self = this;
ul.append("<table class='table table-striped'><thead><tr class='ui-menu-item'><th>" + Translations.SKU + "</th><th>" + Translations.Name + "</th>" +
"<th>" + Translations.Stock + "</th><th>" + Translations.Ordered + "</th><th>" + Translations.BulkOrdered + "</th><th>" + Translations.Underway + "</th>" +
"</tr></thead><tbody></tbody></table>");
$.each(items, function(index, item) {
self._renderItemData(ul.find("tbody"), item);
});
};
});
}


I only need to comment out elm._renderItem and elm._renderMenu to return to the previous behaviour and that works like intended.

Answer

After some more study I found out that it tries to set a class called ui-state-focus on the li-tag and the a-tag contained in it then gets a background and a border.

Since in the modified version above the a-tag was repeated a few times it might have choked on that. I have created an ugly hack that works by creating a faux table with spans with fixed widths, this even works with headers:

   elm._renderItem = function (table, item) {
        return $("<li role='option' class='option' style='width:920px'>")
            .append("<a><div style='width:120px' >" +
                item.SKU +
                "</div><div style='width:500px; overflow:hidden'>" +
                item.Name +
                "</div><div style='width:70px'>" +
                item.Stock +
                "</div><div style='width:70px'>" +
                item.Ordered +
                "</div><div style='width:70px'>" +
                item.BulkOrdered +
                "</div><div style='width:70px'>" +
                item.Underway +
                "</div></a></li>")
            .appendTo(table);
    };

    elm._renderMenu = function(ul, items) {
        var self = this;
        ul.append("<li class='autocomplete-header'><div style='width:120px'>" +
            Translations.SKU +
            "</div><div style='width:500px;overflow:hidden'>" +
            Translations.Name +
            "</div><div style='width:70px'>" +
            Translations.Stock +
            "</div><div style='width:70px'>" +
            Translations.Ordered +
            "</div><div style='width:70px'>" +
            Translations.BulkOrdered +
            "</div><div style='width:80px'>" +
            Translations.Underway +
            "</div></li>");
        $.each(items, function(index, item) {
            self._renderItemData(ul, item);
        });
    };

It's not pretty and probably you should do the column widths with a class instead of hard-coded values but this at least should get you on the way if you experience the same problem.

If there's a better solution I would like to hear it!