How to Add a Kendo Grid to a ComboBox

11 Mar 2016 16:20
Tags combobox grid kendo

Back to list of posts

Overview

In the Telerik Kendo UI Feedback website, there is a suggestion for a Grid in ComboBox. I was interested to see if I could put something together that would satisfy the request. What I came up with was to create a plugin that extended the kendo.ui.ComboBox and in the dropdown list, replace the contents with a Kendo Grid. My solution isn't as elegant as I'm sure the Kendo UI developers would be able to accomplish, but it works.

Here is what it looks like when I start typing in a name in the ComboBox Here is what it looks like when I am filtering on the title column in the grid:
comboboxgrid_filtering.png
comboboxgrid_column_filter.png

Extending the Kendo ComboBox

I started to create the ExtComboBoxGrid plugin by extending the Kendo ComboBox. Here is what I started with:

(function ($, kendo) {
    var ExtComboBoxGrid = kendo.ui.ComboBox.extend({
        options: {
            name: "ExtComboBoxGrid"
        }
    });
    kendo.ui.plugin(ExtComboBoxGrid);
})(window.kendo.jQuery, window.kendo);

Adding the Grid

I researched the Kendo ComboBox and found that the kendo.ui.ComboBox extends kendo.ui.Select which extends kendo.ui.List. In the kendo.ui.List, a list element is created that contains an unordered list of items found in the datasource. The kendo.ui.List creates a kendo.ui.Popup and inserts the list element into the popup that is displayed as needed to show the list of items. What I did was replaced the unordered list with a grid and set the datasource for the combobox as the datasource for the grid. To configure the grid, I added a grid configuration option to the ExtComboBoxGrid for the configuration options for the grid. As a default option, I set the selectable option for the grid to "row". Here is what that looks like:

(function ($, kendo) {
    var ExtComboBoxGrid = kendo.ui.ComboBox.extend({
        options: {
            name: "ExtComboBoxGrid",
            grid: {
                selectable: "row"
            }
        },
 
        init: function (element, options) {
            /// <summary>
            /// Initialize the widget.
            /// </summary>
 
            var that = this;
 
            // Call the base class init.
            kendo.ui.ComboBox.fn.init.call(this, element, options);
 
            // Replace the dropdownlist with a grid.
            this.list.html("<div class='k-ext-grid'></div>");
            this._grid = this.list.find(".k-ext-grid").kendoGrid(
                $.extend({}, this.options.grid, { dataSource: options.dataSource })
            ).data("kendoGrid");
        },
 
        setDataSource: function (dataSource) {
          /// <summary>
          /// When setting the datasource, set the grid datasource.
          /// </summary>
 
            kendo.ui.ComboBox.fn.setDataSource.call(this, dataSource);
 
            this._grid.setDataSource(dataSource);
        }
    });
    kendo.ui.plugin(ExtComboBoxGrid);
})(window.kendo.jQuery, window.kendo);

Grid Height

I needed to set the height of the grid when the dropdown is displayed. To do this, in the init function I subscribed to the ComboBox open event on the first time that it is opened, and set the grid height.

// When the combobox dropdown is displayed for the first time, resize the grid.
this.one("open", function () {
    setTimeout(function () {
    var height = typeof that.options.grid.height === "undefined"
      ? 400
      : that.options.grid.height;
 
    that._grid.wrapper.height(height);
    that._grid.resize();
  }, 100);
});

Grid Row Selection

When a row is selected in the grid, I needed to let the combobox know about it. In the init function, I subscribed to the grid's change event. The event handler get the selected item, and then locates the item in the combobox and selects using the combobox.select function. With the item selected in the combobox, I raised the combobox change event and close the combobox dropdown.

this._grid.bind("change", function () {
    /// <summary>
    /// When an item is selected in the grid, select the item in the combobox.
    /// </summary>
 
    var selectedRows = this.select();
    var dataItem = this.dataItem(selectedRows[0]);
 
    that.select(function (item) {
        return item[that.options.dataValueField] === dataItem[that.options.dataValueField];
    });
 
    that.trigger("change");
    that.close();
});

Grid Paging

When I set the pageable option to { pageSize: 10 } for the grid, I found that the page size wasn't getting set properly on the grid. What I had to do was set the pageSize on the kendo.data.dataSource.

Grid Filtering

When I set the grid filterable option to true, I ran into an issue with the combobox dropdown closing when I clicked on the grid column's filter icon. To handle this, in the init function I overrode the kendo.ui.Popup.close function and only close the popup when the filter menu not being displayed.

this.popup.close = function () {
    /// <summary>
    /// Override the popup.close function and call the Popup close if the user isn't
    /// trying to set a filter.
    /// </summary>
 
    setTimeout(function () {
        if (that.popup.element.find("form.k-filter-menu.k-popup").is(":visible") === false) {
            kendo.ui.Popup.fn.close.call(that.popup);
        }
    }, 100);
}

What I discovered after doing this was that I couldn't click on the input field in the filter menu to start typing in filter criteria. So I had to implement a click event handler on the filter menu input fields and set focus to the input field.

this.popup.element.on("click", "form.k-filter-menu input.k-textbox", function () {
    /// <summary>
    /// Let the user click into the filter menu textbox.
    /// </summary>
 
    $(this).focus();
});

Implementing the ExtComboBoxGrid Widget

Now that I have a working plugin, I can implement it. I create an input field in the HTML as I would for a ComboBox:

<input id="comboBoxGrid" style="width:500px;" />

I create a kendo.ui.DataSource with some data and I set the pageSize so that I can enable paging in the grid"

var employees = new kendo.data.DataSource({
    data: [
        {"id": 1,"fullName":"Anthony Nelson","title":"Junior Quality Assurance Engineer","age":36},
        {"id": 2,"fullName":"Helen Garcia","title":"Principal Systems Engineer","age":43},
        {"id": 3,"fullName":"John Williams","title":"Senior Software Engineer","age":38},
        {"id": 4,"fullName":"Karen Robinson","title":"Quality Assurance Engineer","age":34},
        {"id": 5,"fullName":"Brian Adams","title":"Deputy Director","age":36},
        {"id": 6,"fullName":"Daniel Johnson","title":"Director","age":42},
        {"id": 7,"fullName":"Linda Williams","title":"Systems Engineer","age":69},
        {"id": 8,"fullName":"Helen Turner","title":"Vice-President","age":27},
        {"id": 9,"fullName":"Helen Brown","title":"Senior Software Engineer","age":26},
        {"id": 10,"fullName":"David Phillips","title":"Systems Engineer","age":67},
        {"id": 11,"fullName":"Betty Davis","title":"Principal Quality Assurance Engineer","age":31},
        {"id": 12,"fullName":"Mark Carter","title":"Systems Engineer","age":50},
        {"id": 13,"fullName":"Margaret Thomas","title":"Senior Principal Systems Engineer","age":20},
        {"id": 14,"fullName":"George Adams","title":"Senior Systems Engineer","age":69},
        {"id": 15,"fullName":"Daniel Johnson","title":"Help Desk Engineer","age":60},
        {"id": 16,"fullName":"Mary Turner","title":"Junior Quality Assurance Engineer","age":36},
        {"id": 17,"fullName":"Anthony Roberts","title":"Junior Help Desk Engineer","age":57},
        {"id": 18,"fullName":"Jason Miller","title":"Principal Quality Assurance Engineer","age":22},
        {"id": 19,"fullName":"John Garcia","title":"Senior Systems Engineer","age":54},
        {"id": 20,"fullName":"Paul Wright","title":"Senior Business Analyst","age":43},
        {"id": 21,"fullName":"Kimberly Green","title":"Junior Quality Assurance Engineer","age":54},
        {"id": 22,"fullName":"John Thompson","title":"Senior Principal Help Desk Engineer","age":53},
        {"id": 23,"fullName":"Nancy Martin","title":"Principal Business Analyst","age":28},
        {"id": 24,"fullName":"Susan Nelson","title":"Quality Assurance Engineer","age":69},
        {"id": 25,"fullName":"Karen Perez","title":"Junior Systems Engineer","age":47}
    ],
    pageSize: 10
});

Finally, I initialize an instance of the ExtComboBoxGrid. I implement options on the ComboBox as I normally would; in this example, I set the dataTextField, dataValueField, filter, dataSource and change configuration settings. Additionally, I add a grid setting that is a JSON object with all the grid configuration settings; in this example, I set the columns, pageable, filterable and height:

var comboBoxGrid = $("#comboBoxGrid").kendoExtComboBoxGrid({
    grid: {
        columns: [{
            title: "Name",
            field: "fullName"
        },{
            title: "Title",
            field: "title"
        }],
        pageable: {
            pageSize: 10
        },
        filterable: true,
        height: 400
    },
    dataTextField: "fullName",
    dataValueField: "id",
    filter: "startswith",
    dataSource: employees,
    change: function (e) {
        /// <summary>Write out the employee that was selected.</summary>
 
        var dataItem = this.dataItem();
      $("#console").append(kendo.format("<div>{0}</div>", JSON.stringify(dataItem)));
    }
}).data("kendoExtComboBoxGrid");

Other Features

Since I have only tested out a small portion of the grid features in this plugin, I'm sure there are features that may not work properly without a bit of tweaking. If you run into that, let me know and I'll see what I can do.

jsFiddle

Downloads

kendo.web.plugins.extcomboboxgrid.js

Comments: 0

Add a New Comment

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License