New to Kendo UI for jQuery? Download free 30-day trial

Grid Search and Highlight Rows

Environment

Product Progress® Kendo UI® Grid for jQuery Created with version 2022.2.510

Description

I want to use a search input to find data on the current page of the Grid. I also want to:

  • Highlight the rows that match the search criteria.
  • Select which columns can be searched.

Solution

The search will work only with string values. Numbers and dates will also be treated as strings when a value is typed in the searchbox.

  1. Create a Grid toolbar.template with a search input and an icon for the column menu.
  2. Create a div element for the column menu. The purpose of the column menu is to allow the user to select which columns can be searched.
  3. Initialize the Grid.
  4. Attach an event handler to the dataBound event of the Grid.
  5. Inside the dataBound event, attach an input event handler to the searchbox and initialize a kendo.ui.Popup for the column menu.
  6. In the input event of the search box, get all the columns that are selected in the column menu (all by default).
  7. Iterate over the data of the Grid, and find any cell values that match the input in the search box. The search behavior is treated as contains.
  8. Iterate over the found items and highlight them with CSS.
     <script type='x-kendo/template' id='toolbar'>
        <label>Search:</label>
        <span class="k-input k-textbox k-input-solid k-input-md k-rounded-md">
      <input data-role="textbox" aria-disabled="false" class="search k-input-inner" style='height: 28px;'/>
      </span>
      <span class="search-columns-icon k-icon k-i-gear"></span>
    </script>

    <div id="grid"></div>

    <div class="search-columns-menu">
      <ul class="search-columns-list">
      </ul>
    </div>

    <script>
      $(document).ready(function () {
        $("#grid").kendoGrid({
          toolbar: $("#toolbar").html(),
          dataSource: {
            type: "odata",
            transport: {
              read: "https://demos.telerik.com/kendo-ui/service/Northwind.svc/Orders"
            },
            schema: {
              model: {
                fields: {
                  OrderID: { type: "number" },
                  Freight: { type: "number" },
                  ShipName: { type: "string" },
                  OrderDate: { type: "date" },
                  ShipCity: { type: "string" }
                }
              }
            },
            pageSize: 20,
            serverPaging: true,
            serverFiltering: true,
            serverSorting: true,
            filter: [{field: "Freight", operator: "gte", value: 32}]
          },
          filterable: true,
          pageable: true,
          height: 550,
          sortable: {
            mode: "mixed",
            allowUnsort: true,
            showIndexes: true
          },
          search: {
            fields: [
              { name: "OrderID", operator: "eq" },
              { name: "Freight", operator: "gte" },
              { name: "ShipName", operator: "contains" },
              { name: "ShipCity", operator: "contains" },
            ]
          },
          columns: [
            {
              field: "OrderID",
              title: "Order ID",
            },
            "Freight",
            {
              field: "OrderDate",
              title: "Order Date",
              format: "{0:MM/dd/yyyy}"
            }, {
              field: "ShipName",
              title: "Ship Name"
            }, {
              field: "ShipCity",
              title: "Ship City"
            }
          ]
        });

        // Execute the dataBound event once when the Grid loads.
        $("#grid").data("kendoGrid").one("dataBound", onGridBound);

        function onGridBound() {
          let grid = this;

          // Bind the input event to the search box in the toolbar.
          grid.element.find(".search").on("input", search);

          // Append a title to the popup.
          $(".search-columns-menu").prepend("<h5 class='search-columns-title'>Columns to search</h5>");

          // Initialize a popup for the columns.
          let popup = $(".search-columns-menu").kendoPopup({
            anchor: $(".search-columns-icon"),
          }).data("kendoPopup");

          popup.one("activate", activate);

          // The first time the popup is displayed, populate it with the checkboxes.
          function activate(e) {
            let list = grid.columns.map(c => {
              return "<li><input checked type='checkbox' class='search-checkbox k-checkbox'/>"+c.field+"</li>";
            });

            this.element.find(".search-columns-list").html(list);
            this.element.find(".search-checkbox").on("change", onCheck);

            function onCheck() {
              // When a checkbox is checked/unchecked, trigger the input event of the search box in order to update the found results.
              grid.element.find(".search").trigger("input");
            }
          }

          // When the gear icon is clicked, display the popup.
          $(".search-columns-icon").on("click", function (){
            popup.open();
          });
        }

        function search() {
          let grid = $("#grid").data("kendoGrid"),
              defaultFields = grid.columns.map(c => c.field),
              value = $(this).val(),
              searchData = grid.dataSource.data(),
              searchListElements = $(".search-columns-list li");

          // By default all columns will be searched. Once the popup is opened for the first time, the checked columns will be used instead.
          let searchFields = searchListElements.length ? getCheckedColumns(searchListElements) : defaultFields;

          $(".highlighted").removeClass("highlighted");

          let foundItems = searchData.reduce((result, item) => {
            for(let i=0; i<searchFields.length; i++) {
              let field = searchFields[i];
              let fieldValue = item[field];

              // Change the format of the date so it matches the one in the Date column.
              if(fieldValue instanceof Date) {
                fieldValue = kendo.toString(fieldValue, "MM/dd/yyyy");
              }

              if(value.length > 0 && fieldValue.toString().toLowerCase().indexOf(value.toLowerCase()) > - 1) {
                result.push(item);
              }
            }
            return result;
          }, []);

          foundItems.forEach((item) => {
            let row = grid.element.find("[data-uid='"+item.uid+"']");
            // Highlight the found rows.
            row.addClass("highlighted");
          });
        }

        function getCheckedColumns(searchListElements) {
          let searchFields = [];

          for(let i=0; i<searchListElements.length; i++) {
            let element = $(searchListElements[i]);
            let checked = element.find("input:checked").length;

            if(checked) {
              searchFields.push(element.text()); 
            }
          }

          return searchFields;
        }
      });
    </script>

    <style>
      .highlighted {
        background-color: #0071bc;
        color: #ffffff;
      }

      .search-columns-menu {
        font-family: Arial !important;
        width: 150px;
      }

      .search-columns-list {
        list-style: none;
        padding-left: 5px;
      }

      .search-columns-title {
        text-align: center;
      }

      .search-columns-list li {
        padding-bottom: 10px;
      }
    </style>
In this article