Searching in Infragistics jQuery Hierarchical Grid

Atanas Dyulgerov / Wednesday, March 14, 2012

This article will show you how to load the IG jQuery hierarchical grid with data and enable you to search it from a small external form. It will also show you how to expand the rows that match your search results.

Creating the Hieararchical Grid and Loading it with data

Lets start with creating the hierarchical grid and load it with data. If you know how to do that you can safely jump to the next section “Creating the Search UI and Logic” The first thing that we need to do is set up the environment in which we’ll create the grid. That includes providing the required JS scripts and CSS files. We need the jQuery and the jQuery UI scripts. In addition to them we need the IG UI base JS file. The easiest way to start using those scripts is to provide links to the respective CDN locations. Here is how to do that for an HTML page.

  1. <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
  2. <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js" type="text/javascript"></script>
  3. <script src="http://cdn-na.infragistics.com/jquery/20112/2045/js/combined/min/ig.ui.min.js" type="text/javascript"></script>

You also need some basic css styles to get the default look of the Infragistics combo box. Again for an HTML page here is what you need to include

  1. <link href="http://cdn-na.infragistics.com/jquery/20112/2045/themes/min/base/ig.ui.min.css" rel="stylesheet" type="text/css" />
  2. <link href="http://cdn-na.infragistics.com/jquery/20112/2045/themes/min/ig/jquery.ui.custom.min.css" rel="stylesheet" type="text/css" />

Note that the URL for the Infragistics CDN includes format of the type …jquery/xxxxx/yyyy/js…. the xxxxx is the release version, 20112 is the latest as of the time of writing this article. The other number is the build that you want to use. By the time you read this there might be a newer version and you might want to change that number if you want to use it instead. Note also that all those files come with the product download and you are not required to use the CDN.

Once we have all this in place we can add a div that will be our hierarchical grid and work on it. I’ll set its id to hierarchicalGrid. Before we transform this div in a hierarchical grid we need to figure out what data we’ll fill the grid with. For this demo I’ll use the free odata service that exposes the Nortwind database in a JSONP format. 

So far we have code that looks something like this:

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3.  
  4. <head>
  5.     <title>Search in the Infragistics jQuery Hierarchical Grid</title>
  6.     
  7.     <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
  8.     <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js" type="text/javascript"></script>
  9.     <script src="http://cdn-na.infragistics.com/jquery/20112/2045/js/combined/min/ig.ui.min.js" type="text/javascript"></script>
  10.     
  11.     <link href="http://cdn-na.infragistics.com/jquery/20112/2045/themes/min/base/ig.ui.min.css" rel="stylesheet" type="text/css" />
  12.     <link href="http://cdn-na.infragistics.com/jquery/20112/2045/themes/min/ig/jquery.ui.custom.min.css" rel="stylesheet" type="text/css" />
  13. </head>
  14.  
  15. <body>
  16.     <div>
  17.         <div id="hierarchicalGrid" />
  18.     </div>
  19. </body>
  20.  
  21. </html>

To load the grid with data we have to subscribe to the load event of the window and then do some initializing. I’ll show you the script code to do that first and then I’m going to explain what everything does:

  1. <script type="text/javascript">
  2.     $(window).load(function () {
  3.         var parentGrid,
  4.             allParentRows,
  5.             url = 'http://services.odata.org/Northwind/Northwind.svc/Orders?$format=json&$top=50&$callback=?',
  6.             jsonp = new $.ig.JSONPDataSource({ dataSource: url, responseDataKey: "d" }),
  7.             CONST = {
  8.                 inputEmptyValue: "Empty Value",
  9.                 foundedResults: "Found results for "
  10.             };
  11.  
  12.         $("#hierarchicalGrid").igHierarchicalGrid({
  13.             initialDataBindDepth: 0,
  14.             odata: true,
  15.             dataSource: jsonp,
  16.             responseDataKey: 'd',
  17.             rendered: function (e, args) {
  18.                 parentGrid = $("#hierarchicalGrid").igHierarchicalGrid("rootWidget");
  19.                 allParentRows = parentGrid.allRows();
  20.             },
  21.             autoGenerateColumns: false,
  22.             primaryKey: "OrderID",
  23.             columns: [
  24.                 { key: "OrderID", headerText: "Order ID", dataType: "number", width: "100px" },
  25.                 { key: "CustomerID", headerText: "Customer ID", dataType: "string", width: "100px" },
  26.                 { key: "Freight", headerText: "Freight", dataType: "string", width: "100px" },
  27.                 { key: "ShipName", headerText: "Ship Name", dataType: "string", width: "300px" },
  28.                 { key: "ShipCountry", headerText: "Ship Country", dataType: "string", width: "150px" }
  29.             ],
  30.             childrenDataProperty: "Employee",
  31.             autoGenerateLayouts: false,
  32.             columnLayouts: [
  33.                 {
  34.                     key: "Employee",
  35.                     responseDataKey: 'd',
  36.                     autoGenerateColumns: true,
  37.                     primaryKey: "EmployeeID",
  38.                     foreignKey: "OrderID",
  39.                     columns: [
  40.                         { key: "FirstName", headerText: "First Name", dataType: "string" },
  41.                         { key: "LastName", headerText: "Last Name", dataType: "string" },
  42.                         { key: "Title", headerText: "Title", dataType: "string" },
  43.                         { key: "City", headerText: "City", dataType: "string" },
  44.                     ]
  45.                 }
  46.             ]
  47.         });
  48.     });
  49. </script>

The first few lines of the script define the data source the grid will use. The url points to the service’s address that returns some data in the proper format. The jsonp variable will be assigned later as a dataSource.

The $("#hierarchicalGrid").igHierarchicalGrid() method transforms the div to a hierarchical grid and initializes it with the properties needed to load it with the data. The format is specified, the data source and columns are defined, including the hierarchical ones.

On the main level of the hierarchical grid we’ll have order records and the sub level we’ll have employees that are associated with those orders. The primary keys and foreign key that define the hierarchy are present too.

Note that those are the columns don’t expose all the properties of the records that we receive. Those are used just for the demo. You can include as many as you want in your real app.

With this we have a working hierarchical grid loaded with data and set up to hierarchize it appropriately. The next step will implement the search logic and interface.

Creating the Search UI and Logic

The first thing to do to implement the searching in the grid is to create a small form that will allow us to input text to search, and will provide two buttons: search and clear search.

Here is the code for it:

 

  1. <fieldset class="searchWrapper">
  2.     <legend>Search In Hierarchical Grid</legend>
  3.     <div class="search-container">
  4.         <input id="inpSearch" type="text" value="VINET" />
  5.     </div>
  6.     <div class="search-container">
  7.         <input id="btnSearch" type="button" value="Search" />
  8.         <input id="btnClear" type="button" value="Clear" />
  9.     </div>
  10. </fieldset>

 

When we click on the btnSearch we will do the actual search with the contents of inpSearch and when we click on btnClear we will remove the filtering. For each search result we will expand the grid’s row and for all the rows that are not a match we’ll collapse them. Lets throw some style for that code before we go into the interesting code logic that does the search and expand/collapse.

 

  1. <style type="text/css">
  2.     .search-container
  3.     {
  4.         margin: 5px 0;
  5.     }
  6.     .search-container input[type="button"]
  7.     {
  8.         width: 100px;
  9.     }
  10.     .searchWrapper
  11.     {
  12.         border: solid 1px #000;
  13.         margin: 20px 0;
  14.         padding: 5px 7px 5px 20px;
  15.         width: 750px;
  16.     }
  17.     .clear
  18.     {
  19.         clear: both;
  20.     }
  21. </style>

 

To handle the search and clear button clicks we need to hock up to the click event of each of those elements with an appropriate handler.

 

  1. $("#btnSearch").click(function () {
  2.     findRows($("#inpSearch").val());
  3. });
  4. $("#btnClear").click(function () {
  5.     clearSearch();
  6. });

 

Now we have to implement the clearSearch and findRows functions. The general logic that we’ll follow is that for each row in the grid we will call a method searchCells with parameters the row’s cells as an array and the search value. If one of the cells’ value contains the search value the row is expanded, if not – collapsed. This could be replaced with some other logic, like counting matches, filtering of the data source, etc. The clear function will go and collapse all expanded rows. Here is the code:

 

  1. function findRows(searchValue) {
  2.     if ($.trim(searchValue).length > 0) {
  3.         for (var rowIndex = 0; rowIndex < allParentRows.length; rowIndex++) {
  4.             if (searchCells(allParentRows[rowIndex], searchValue)) {
  5.                 if (!$("#hierarchicalGrid").igHierarchicalGrid("expanded", allParentRows[rowIndex])) {
  6.                     $("#hierarchicalGrid").igHierarchicalGrid("expand", allParentRows[rowIndex]);
  7.                 }
  8.             } else {
  9.                 if ($("#hierarchicalGrid").igHierarchicalGrid("expanded", allParentRows[rowIndex])) {
  10.                     $("#hierarchicalGrid").igHierarchicalGrid("collapse", allParentRows[rowIndex]);
  11.                 }
  12.             }
  13.         }
  14.     } else {
  15.         clearSearch();
  16.     }
  17. }
  18.  
  19. function searchCells(row, searchCellValue) {
  20.     // Ignore first column, because it contains the expand/collapse image.
  21.     for (var cellIndex = 1; cellIndex < row.cells.length; cellIndex++) {
  22.         var cellValue = " " + $(row.cells[cellIndex]).html() + " ";
  23.         if (cellValue.toLowerCase().indexOf(searchCellValue.toLowerCase()) >= 0) {
  24.             return true;
  25.         }
  26.     }       
  27.     return false;
  28. }
  29.  
  30. function clearSearch() {
  31.     for (var rowIndex = 0; rowIndex < allParentRows.length; rowIndex++) {
  32.         if ($("#hierarchicalGrid").igHierarchicalGrid("expanded", allParentRows[rowIndex])) {
  33.             $("#hierarchicalGrid").igHierarchicalGrid("collapse", allParentRows[rowIndex]);
  34.         }
  35.         $("#inpSearch").val("");
  36.     }
  37. }

 

Note that the actual cells are located in the cells property of each row and the collection with rows allParentRows is initialized with the parentGrid.allRows() method in the hierarchical grid initialization in the beginning of the article.

This is all you need in order to implement searching in the hierarchical grid. The last thing I want to mention is that if you want to make the buttons look as nice as in the screenshot in the beginning of the article you can make them IG Buttons by calling the igButton() and setting the appropriate labelText at the lines where you attach to the click events. Here is how the button and click event handler code will look like for the btnSearch:

 

  1. $("#btnSearch").igButton({ labelText: $("#btnSearch").val() }).click(function () {
  2.     findRows($("#inpSearch").val());
  3. });

 

Here is a working demo of the whole sample. You can view the complete code by looking at the source of the page.

I hope this article has been interesting and useful.

Have a great day!