PDA

View Full Version : rowexpander collapsing after store reload



extAsplode
23 Jul 2010, 1:11 PM
Ext newb here, but I've been scouring the forums for a long time looking for a solution here. I'm using Ext 3.2.1. I have a GridPanel with a rowexpander as the first column in the ColumnModel. When I execute a store.reload() on the grid's store, the rows that were previously expanded with rowexpander get collapsed, and I can't expand or collapse after the reload at all until I reload the page entirely with a browser reload. Any rows that I hadn't expanded prior to the reload still work - it's only the ones that I had previously expanded that break.

I've tried: setting enableCaching: false on the rowexpander, verifying that the store has a valid idProperty set to a field that ensures uniqueness for the rows in the store, forcing the rowexpander with expandRow after the store.reload(), but no combination of these approaches has worked thus far.

Any help would be greatly appreciated!

Thanks,
Andy

Condor
25 Jul 2010, 5:58 AM
You might need to configure the RowExpander with lazyRender:false.

extAsplode
26 Jul 2010, 6:56 AM
Thanks for the reply. Unfortunately, if I set lazyRender: false in the rowexpander, I get an error: "this.tpl is undefined" which is inside of the rowexpander's getBodyContent...



getBodyContent : function(record, index){
if(!this.enableCaching){
return this.tpl.apply(record.data);
}
var content = this.bodyContent[record.id];
if(!content){
content = this.tpl.apply(record.data);
this.bodyContent[record.id] = content;
}
return content;
}

Any additional ideas?

Thanks,
Andy

Condor
26 Jul 2010, 7:01 AM
There's something funky going on in your code.

Can you post how you create your grid and expander and how you reload it?

extAsplode
26 Jul 2010, 7:26 AM
Ok here goes. Here's the code around creating the rowexpander and the grid and reloading the store associated with the grid. At a high level, what I'm trying to do is to have a parent GridPanel with the rowexpander as the first column in the ColumnModel. When a row is expanded, I display a TabPanel that has a child EditorGridPanel inside of that.



//The row expander
var rowExpander = new Ext.ux.grid.RowExpander({
listeners: {
expand: function(rowex, record, body, index){
if (!this.loaded || !this.loaded[index]) {
new Ext.TabPanel({
id: 'TabPanel' + record.id,
renderTo: body,
activeTab: 0,
style: {
margin: '0 10px 10px 10px'
},
items: [{
title: 'Tab title here',
items: [{
html: 'a child EditorGrid actually goes here... removing for brevity'
}]
}]
}));

this.loaded = this.loaded || [];
this.loaded[index] = true;
}
}
}
});

//Consuming the rowexpander in the ColumnModel
var colModel = new Ext.grid.ColumnModel({
defaults: {
menuDisabled: true
},
columns: [rowExpander, {
header: 'Column 1',
dataIndex: 'Column1',
sortable: true,
width: 75
}
//additional columns removed for brevity
]
});

//The parent grid
var config = {
id: 'TradesPanel',
layout: 'fit',
region: 'center',
title: 'The title',
items: [{
id: 'TradesGrid',
store: store,
loadMask: true,
selModel: new Ext.grid.RowSelectionModel({
listeners: {
//Before we're dealing with a nested grid situation, we need to cancel
//the selection event on the outer grid or else weird things happen.
beforerowselect: function(selectionModel, rowIndex, colIndex){
return false;
}
}
}),
colModel: colModel,
plugins: rowExpander,
autoHeight: true,
viewConfig: {
deferEmptyText: true,
emptyText: 'No records found.'
}
}]
};

//Reloading the store attached to the parent grid. This is where the rowexpander stops working.
Ext.getCmp('TradesGrid').store.reload(store.lastOptions);

Thanks,
Andy

Condor
26 Jul 2010, 7:49 AM
So you are rendering components into the expander? That can cause huge memory leaks!

Reloading a store will destroy all grid rows and it will remove all the tabpanels from the DOM, but not from memory!

1. I suggest changing the code to store the tabpanel in 'loaded' instead of 'true'.
2. If you do that you can destroy all tabpanels and clear 'loaded' before reloading the store.
3. After reloading you need to manually call expand on all rows that have an expanded state.

extAsplode
27 Jul 2010, 6:36 AM
Thank you very much! After I applied your 3 suggestions, it started working! I also found though that the asynchronous nature of a store's reload was causing some trouble, so I ended up utilizing a callback function so that the store is ready before I manually expand the rows.

Thanks!
Andy

istetska
23 Sep 2010, 11:13 AM
Andy
I'm having the same problem as you had. Can you please share your piece of code "after applying the 3 suggestions mentioned above"?

I would relly appreciate your help

istetska
23 Sep 2010, 11:14 AM
Andy
I'm having the same problem as you had. Can you please share your piece of code "after applying the 3 suggestions mentioned above"?

I would really appreciate your help

Regards
Irena

extAsplode
23 Sep 2010, 1:20 PM
Ok here goes. You will definitely have to tweak this for your purposes, but you should be able to adapt this code fairly easily I think - if you have trouble, just post again and let me know. The following function runs in order to reset the rowexpanders. Ext.getCmp('TradesPanel') refers to the parent grid that contains the rowexpanders in the first column of the grid. In my case, when a rowexpander is expanded, it displays a TabPanel control with a grid (referenced in the code below as "InvitedCompanies..." inside of the TabPanel. In the code below, rowexpander.loaded holds a reference to these TabPanel controls so that it can be destroyed in the code below for the sake of memory management.



/**
* When we reload the trades store, all rows under the TradesGrid get destroyed.
* This method ensures that the store reload happens such that memory is managed
* and rowExpanders return to their proper expanded/collapsed state.
* See Andy's forum thread on the topic here: http://www.sencha.com/forum/showthread.php?105163-rowexpander-collapsing-after-store-reload
*/
var resetRowExpanders = function(){
//Get a reference to each InvitedCompanies grid that has been expanded
var tradesPanel = Ext.getCmp('TradesPanel');
var ts = Ext.getCmp('TradesGrid').store;
var expandedInvitedCompaniesGrids = [];
var tradeCount = ts.data.keys.length;
for (var k = 0; k < tradeCount; k++) {
var inviteGrid = Ext.getCmp('InvitedCompanies' + ts.data.keys[k] + 'Grid');
if (inviteGrid) {
expandedInvitedCompaniesGrids.push(inviteGrid);
}
}

if (expandedInvitedCompaniesGrids.length !== 0) {
//Refresh the InvitedCompanies stores
for (var i = expandedInvitedCompaniesGrids.length; i--;) {
var store = expandedInvitedCompaniesGrids[i].store;
store.reload(store.lastOptions);
}

//Memory management. Destroy the TabPanels that were created by the rowExpander.
for (var j = tradesPanel.rowExpander.loaded.length - 1; j > -1; j--) {
if (tradesPanel.rowExpander.loaded[j]) {
tradesPanel.rowExpander.loaded[j].destroy();
}
}

//Clear the rowExpander's loaded array which previously stored references to the TabPanels
if (tradesPanel.rowExpander.loaded) {
tradesPanel.rowExpander.loaded = undefined;
}

//Get the current Expanded/Collapsed state of the row expanders
var stateToRestore = tradesPanel.rowExpander.state;

var autoExpandRows = function(stateToRestore){
var rowExpander = Ext.getCmp('TradesPanel').rowExpander;

//Iterate through the keys collection looking for keys that match with the
//contents of the rowexpander's state object.
var tradesStore = Ext.getCmp('TradesGrid').store;
for (var i = 0; i < tradesStore.data.keys.length; i++) {
if (stateToRestore && stateToRestore[tradesStore.data.keys[i]]) {
tradesPanel.rowExpander.expandRow(i);
}
}
};

var storeLoadedCallback = function(r, options, success){
if (success) {
//Re-expand any trades that were previously expanded
autoExpandRows(stateToRestore);
}
else {
//Re-set all rowExpanders to be collapsed
var rowex = Ext.getCmp('TradesPanel').rowExpander;
var rowCount = Ext.getCmp('TradesGrid').store.data.length;
for (var i = 0; i < rowCount; i++) {
rowex.collapseRow(i);
}
}
};
}

//Refresh the Trades stores. This causes the rowexpander to collapse though.
store = Ext.getCmp('TradesGrid').store;
if (expandedInvitedCompaniesGrids.length === 0) {
store.reload();
}
else {
store.reload({
callback: storeLoadedCallback
});
}
};


I hope this helps!

Andy

MarcoMalar
12 Sep 2011, 6:43 AM
The answer to the initial problem can be found here:
http://www.sencha.com/forum/showthread.php?90760-Extended-Grid-renderer-problem-with-store-update&highlight=subgrid