2

This is my first time working with Kendo UI. I have a Kendo UI grid with child nodes. I want to retain the expanded rows after databinding. Right now its getting collapsed after a row is added in the child

I have tried suggestion from here

dataBound: function() {
    this.expandRow(this.tbody.find("tr.k-master-row").first());
}

But this expands the first row only.

How to retain rows? What am I missing?

Codepen

Community
  • 1
  • 1
Okky
  • 10,338
  • 15
  • 75
  • 122
  • You want to save state between reads, correct? Then you need to store a reference to the row you expanded prior to doing anything else that might cause the row to collapse. It then becomes academic when expanding the row after the grid is dataBound - you have its reference stored in a variable. – Brett Jul 30 '14 at 14:26
  • @Brett I have tried adding a class in the opened rows and tried to retain them in `dataBoud`, but somehow all of my rows are collapsed before dataBound is triggered. – Okky Jul 31 '14 at 04:06
  • I know its frustrating, and it makes you wonder why altering a master row's detail row should rebind the whole grid is beyond me. But the strategy is sound - you hook into `dataBound` to re-expand the row _after_ the data is bound to the grid. They key obstacle to this problem is figuring out how to store a reference to a row... – Brett Jul 31 '14 at 05:28
  • Look at my solution at the bottom. I store some unique id that is the Id of the data item in my row. I then simply look for this row again on databound and simply expand the row again. – 130nk3r5 Oct 22 '14 at 09:33

3 Answers3

4

After a lot of playing around with your code example in CodePen, I believe I've come up with an elegant solution that works.

Having worked with Kendo UI for over three years, I've become pretty familiar with some of its inner workings. As such, I'm going to take advantage of one of these - the data-uid attribute. Kendo UI puts these on all <tr> elements in its grid. I chose this attribute because I know that when we call grid.expandRow() we're going to need to fashion a valid jQuery selector to pass in as a parameter. This eliminates the need for us to add our own attributes or classes and the code to handle them.

First, we need to define a variable to hold our row reference. We'll call it expandedRowUid. To set its value, we hook into the detailExpand event of the grid. So, when the user expands a row, we store its data-uid number.

var expandedRowUid;

var grid = $('#grid').kendoGird({
  // ...
  detailExpand: function(e) {
    expandedRowUid = e.masterRow.data('uid');
  }
});

Then, whenever a change is made that causes the master grid to re-bind to its data, we hook into the dataBound event of the grid and re-expand the row that has a data-uid equal to the one stored in expandedRowUid.

var grid = $('#grid').kendoGird({
  // ...
  detailExpand: function(e) {
    expandedRowUid = e.masterRow.data('uid');
  },
  dataBound: function() {
    this.expandRow($('tr[data-uid=' + expandedRowUid + ']'));
  }
});

Here is the working CodePen example.

NOTE: This will only re-expand the last row that was expanded before the data bind is triggered. So, if you expand rows 4, 5, and 2 in that order, and then trigger a data bind, only row 2 will be re-expanded. You can obviously extend this functionality to handle use cases like that though.

Brett
  • 4,268
  • 1
  • 13
  • 28
  • Thanks so much man. I haven't thought of this. I have tried with adding a class for expanded row and removing for collapsed since but it didn't work. This is perfect. Thanks again – Okky Jul 31 '14 at 06:06
  • Can you have a look into http://stackoverflow.com/questions/25153797/uncaught-object-error-kendo-grid-read-issue – Okky Aug 06 '14 at 06:41
1
GridDetailExpand: function (e) {
   var gridId = e.sender.element[0].id;
   var grid = $("#" + gridId).data("kendoGrid");
   var data = grid.dataItem(e.masterRow);
   addToArray(expandedRows, data.UniqueIdOfYourDataInGrid);
  },
  GridDetailCollapse: function (e) {
   var gridId = e.sender.element[0].id;
   var grid = $("#" + gridId).data("kendoGrid");
   var data = grid.dataItem(e.masterRow);
   removeFromArray(expandedRows, data.UniqueIdOfYourDataInGrid);
  }

And then on databound

var gridId = e.sender.element[0].id;
var grid = $("#" + gridId).data("kendoGrid");
$.each(grid.tbody.find('tr.k-master-row'), function () {
 var data = grid.dataItem(this);
 if (isInArray(expandedRows, data.UniqueIdOfYourDataInGrid)) {
   grid.expandRow(this);
 }
});

Functions required:

var expandedRows = [];

function addToArray(arr, value) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] === value) return;
    }

    arr.push(value);
}

function removeFromArray(arr, value) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] === value) {
            delete arr[i];
            return;
        }
    }
}

function isInArray(arr, value) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] === value) return true;
    }

    return false;
}

Hope this helps ... took me a while to figure it out...

Pete
  • 3,842
  • 3
  • 31
  • 42
130nk3r5
  • 1,120
  • 10
  • 12
0

Solution for Retaining Last Expanding row in the parent grid after records added in the child grid get refreshed.

 detailInit: function (e) {
   
    //Get Parent Grid Last expanded Row index
    lastRowIndex = $(e.masterRow).index(".k-master-row");
   
 },
 dataBound: function () {
   
    //Check any parent grid row is expanded based on row index
    if (lastRowIndex != null && lastRowIndex != undefined){
      
      //find the Grid row details based on row index
      var row = $(this.tbody).find("tr.k-master-row:eq(" + lastRowIndex + ")");
      
      //If expand Row exists then it will expanded
      this.expandRow(row);
    }
    else {
      
      //None of the Parent Grid row is expanded then,default First row is expanded
      this.expandRow(this.tbody.find("tr.k-master-row").first());
      
    }
}
Umapathy
  • 83
  • 11
  • I was thinking of using something like this but if your grid has any sorting on it the row indexes will change after a data refresh. – BGTurner Mar 27 '18 at 10:45