PDA

View Full Version : [2.0] Ext.ux.grid.SubTableRowExpander: Foldable Rows for Grid



timo.nuros
24 Mar 2008, 6:02 AM
Hi,

this is a Plugin which extends the example grid3 row extender.

Notes:
- The data you read via the store needs to have a field where your sub-records are located in. You need to have exactly the same columns in your sub-records as in your main ones. This means: If you have the columns "company", "value" and "date" in your main records, you also need to have the columns "company", "value" and "date" in your sub-records.
- You need to pass the name of that field using the config field 'subdata'. If you don't specify a field name, it defaults to 'subdata'.
- All records are displayed in the expanded row as seen below in the screenshot. Right now, this is only a display plugin; it won't work with an EditorGrid.
- The plugin re-renders and re-builds the template whenever you hide or show columns and whenever you resize columns. Do not use this with a huge amount of columns! This plugin is meant to be used with a PagingToolbar. Feel free to implement caching yourself
- You can see how the data for the subtable is stored in the example. If you use the ArrayReader, specify 'array' for the reader value, otherwise 'json' is specified. 'json' is also the default value.

Known Issues:
- Column Alignment might be off some pixels. I have no clue why, and I really don't have the time to dig that deep into Ext's CSS code.

Other notes:
- I cannot provide support for this one. Feel free to report bugs anyways, maybe I'll fix them - but don't expect that.
- If you fix a bug, post it here so I can put it together for other users.

Example code:


/*
* Ext JS Library 2.0.2
* Copyright(c) 2006-2008, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/


Ext.onReady(function(){

Ext.QuickTips.init();

var xg = Ext.grid;

// shared reader
var reader = new Ext.data.ArrayReader({}, [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'},
{name: 'industry'},
{name: 'subdata'},
{name: 'desc'}

]);

////////////////////////////////////////////////////////////////////////////////////////
// Grid 1
////////////////////////////////////////////////////////////////////////////////////////
// row expander
var expander = new Ext.ux.SubTableRowExpander({
subdata: 'subdata',
reader: 'array'
});

expander.on("subdblclick", function (r) { alert(r.data.company); });

var grid1 = new xg.GridPanel({
store: new Ext.data.Store({
reader: reader,
data: xg.subRowDummyData
}),
cm: new xg.ColumnModel([
expander,
{id:'company',header: "Company", width: 40, sortable: true, dataIndex: 'company'},
{header: "Price", width: 20, sortable: true, renderer: Ext.util.Format.usMoney, dataIndex: 'price'},
{header: "Change", width: 20, sortable: true, dataIndex: 'change'},
{header: "% Change", width: 20, sortable: true, dataIndex: 'pctChange'},
{header: "Last Updated", width: 20, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
]),
viewConfig: {
forceFit:true
},
width: 600,
height: 300,
plugins: expander,
collapsible: true,
animCollapse: false,
title: 'Expander Rows, Collapse and Force Fit',
iconCls: 'icon-grid',
renderTo: document.body
});

});

Ext.grid.subRowDummyData = [
['3m Co',71.72,0.02,0.03,'9/1 12:00am', 'Manufacturing',
[
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am', 'Manufacturing'],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am', 'Services'],
['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am', 'Manufacturing']
]
],
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am', 'Manufacturing',
[
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am', 'Manufacturing'],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am', 'Services'],
['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am', 'Manufacturing']
]
],
['Altria Group Inc',83.81,0.28,0.34,'9/1 12:00am', 'Manufacturing',
[
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am', 'Manufacturing'],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am', 'Services'],
['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am', 'Manufacturing']
]
],
['American Express Company',52.55,0.01,0.02,'9/1 12:00am', 'Finance',
[
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am', 'Manufacturing'],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am', 'Services'],
['E.I. du Pont de Nemours and Company',40.48,0.51,1.28,'9/1 12:00am', 'Manufacturing']
]
]
];


Plugin code:


Ext.grid.RowExpander = function(config){
Ext.apply(this, config);

this.addEvents({
beforeexpand : true,
expand: true,
beforecollapse: true,
collapse: true
});

Ext.grid.RowExpander.superclass.constructor.call(this);

if(this.tpl){
if(typeof this.tpl == 'string'){
this.tpl = new Ext.Template(this.tpl);
}
this.tpl.compile();
}

this.state = {};
this.bodyContent = {};
};

Ext.extend(Ext.grid.RowExpander, Ext.util.Observable, {
header: "",
width: 20,
sortable: false,
fixed:true,
menuDisabled:true,
dataIndex: '',
id: 'expander',
lazyRender : true,
enableCaching: true,

getRowClass : function(record, rowIndex, p, ds){
p.cols = p.cols-1;
var content = this.bodyContent[record.id];
if(!content && !this.lazyRender){
content = this.getBodyContent(record, rowIndex);
}
if(content){
p.body = content;
}

return this.state[record.id] ? 'x-grid3-row-expanded' : 'x-grid3-row-collapsed';
},

init : function(grid){
this.grid = grid;

var view = grid.getView();
view.getRowClass = this.getRowClass.createDelegate(this);

view.enableRowBody = true;

grid.on('render', function(){
view.mainBody.on('mousedown', this.onMouseDown, this);
}, this);
},

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;
},

onMouseDown : function(e, t){
if(t.className == 'x-grid3-row-expander'){
e.stopEvent();
var row = e.getTarget('.x-grid3-row');
this.toggleRow(row);
}
},

renderer : function(v, p, record){
p.cellAttr = 'rowspan="2"';
return '<div class="x-grid3-row-expander">&#160;</div>';
},

beforeExpand : function(record, body, rowIndex){
if(this.fireEvent('beforeexpand', this, record, body, rowIndex) !== false){
if(this.tpl && this.lazyRender){
body.innerHTML = this.getBodyContent(record, rowIndex);
}

return true;
}else{
return false;
}
},

toggleRow : function(row){
if(typeof row == 'number'){
row = this.grid.view.getRow(row);
}
this[Ext.fly(row).hasClass('x-grid3-row-collapsed') ? 'expandRow' : 'collapseRow'](row);
},

expandRow : function(row){
if(typeof row == 'number'){
row = this.grid.view.getRow(row);
}
var record = this.grid.store.getAt(row.rowIndex);
var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);
if(this.beforeExpand(record, body, row.rowIndex)){
this.state[record.id] = true;
Ext.fly(row).replaceClass('x-grid3-row-collapsed', 'x-grid3-row-expanded');
this.fireEvent('expand', this, record, body, row.rowIndex);
}
},

collapseRow : function(row){
if(typeof row == 'number'){
row = this.grid.view.getRow(row);
}
var record = this.grid.store.getAt(row.rowIndex);
var body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true);
if(this.fireEvent('beforcollapse', this, record, body, row.rowIndex) !== false){
this.state[record.id] = false;
Ext.fly(row).replaceClass('x-grid3-row-expanded', 'x-grid3-row-collapsed');
this.fireEvent('collapse', this, record, body, row.rowIndex);
}
}
});

Ext.ux.SubTableRowExpander = function(config){
if (!config.subdata) { config.subdata = 'subdata'; }
Ext.apply(this, config);

Ext.ux.SubTableRowExpander.superclass.constructor.call(this);

this.state = {};
this.bodyContent = {};

};


Ext.extend(Ext.ux.SubTableRowExpander, Ext.grid.RowExpander, {
enableCaching: false,

init: function (grid) {

this.addEvents({
dblclick: true,
mouseover: true,
mouseout: true,
subdblclick: true
});

var ret = Ext.ux.SubTableRowExpander.superclass.init.call(this, grid);

this.grid.view.afterMethod('onColumnHiddenUpdated', this.reconfigureTemplate, this);
this.grid.view.afterMethod('onLayout', this.reconfigureTemplate, this);
this.grid.view.afterMethod('onColumnWidthUpdated', this.doWidth, this);
this.grid.view.afterMethod('onAllColumnWidthsUpdated', this.doAllWidths, this);
this.grid.view.afterMethod('afterMove', this.doAllWidths, this);

this.grid.on('dblclick', this.onDblClick, this);

this.grid.store.on('load', function (store, records) { this.createSubdata(); }.createDelegate(this));
this.createSubdata();

this.on("expand", function (e, record) {
var res = Ext.query("table.x-grid3-row-subtable");

for (var i=0;i<res.length;i++) {

Ext.fly(res[i]).on("mouseover", this.onMouseOver);
Ext.fly(res[i]).on("mouseout", this.onMouseOut);
}

for (var i=0;i<record.subdata.records.length;i++) {

Ext.fly("subtable-" + records.records[i].id).on("mouseover", this.onMouseOver);
Ext.fly("subtable-" + records.records[i].id).on("mouseout", this.onMouseOut);
}



});

},
renderer : function(v, p, record){
p.cellAttr = 'rowspan="2"';
return '<div class="x-grid3-row-expander">&#160;</div>';
},
createSubdata: function () {

switch (this.reader) {
case "array":
var reader = new Ext.data.ArrayReader({}, this.grid.store.reader.recordType);
break;
case "json":
default:
var reader = new Ext.data.JsonReader({}, this.grid.store.reader.recordType);
break;
}

for (j=0;j<this.grid.getStore().getCount();j++) {
var record = this.grid.getStore().getAt(j);

if (record.data[this.subdata] && record.data[this.subdata].length > 0) {
record.subdata = this.processRenderMethod(reader.readRecords(record.data[this.subdata]));
} else {
record.subdata = {};
record.subdata.records = new Array();
}
}
},
doWidth: function () {
this.reconfigureTemplate();
this.updateRows();
},
onDblClick : function(e){
var t = e.target;

if (Ext.fly(t.id)) {
var target = Ext.fly(t.id);
if (target.hasClass("x-grid3-cell-subtablerow")) {

var parent = target.findParent("tr.x-grid3-subtable-outertable-row", 10);

var parent2 = target.findParent(this.grid.view.rowSelector, 20);
var record = this.grid.store.getAt(parent2.rowIndex).subdata.records[parent.rowIndex];

this.fireEvent("subdblclick", record);
}
}
},
onMouseOver: function (e) {
var t = e.target;

if (Ext.fly(t.id)) {
var target = Ext.fly(t.id);
if (target.hasClass("x-grid3-cell-subtablerow")) {

var parent = target.findParent("table.x-grid3-row-subtable", 10, true);
parent.addClass("x-grid3-row-over");
}
}
},
onMouseOut: function (e) {
var t = e.target;

if (Ext.fly(t.id)) {
var target = Ext.fly(t.id);
if (target.hasClass("x-grid3-cell-subtablerow")) {
var parent = target.findParent("table.x-grid3-row-subtable", 10, true);
parent.removeClass("x-grid3-row-over");

}
}
},
fly : function(el){
if(!this._flyweight){
this._flyweight = new Ext.Element.Flyweight(document.body);
}
this._flyweight.dom = el;
return this._flyweight;
},
updateRow: function (row) {
var record = this.grid.store.getAt(row);

if(typeof row == 'number'){
row = this.grid.view.getRow(row);
}

var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);

records = record.subdata;

var content = this.tpl.apply(records.records);

this.bodyContent[record.id] = content;
body.innerHTML = content;

},
updateRows: function () {
var ns = this.grid.view.getRows();
for(var i = 0, len = ns.length; i < len; i++){
this.updateRow(i);
}
},
doAllWidths: function () {
this.reconfigureTemplate();
this.updateRows();
},
getActivatedGridColumns: function () {
var cm = this.grid.getColumnModel();

var cols = [];



for(var i = 0; i < cm.getColumnCount(); i++){
if (!cm.isHidden(i)) {
var col = {};
var name = cm.getDataIndex(i);
col.name = (typeof name == 'undefined' ? this.ds.fields.get(i).name : name);
col.index = i;
col.width = this.getColumnWidth(i);
col.renderer = cm.getRenderer(i);
cols.push(col);
}
}

return cols;
},
getColumnWidth : function(col){
var cm = this.grid.getColumnModel();

var w = cm.getColumnWidth(col);
if(typeof w == 'number'){
w = (Ext.isBorderBox ? w : (w-this.grid.view.borderWidth > 0 ? w-this.grid.view.borderWidth:0));
}

return w;
},

reconfigureTemplate: function () {
var cols = this.getActivatedGridColumns();

var template = [
'<table class="x-grid3-subtable-outertable" cellspacing="0">',
'<tpl for=".">'
];



var padding, colWidth;

template.push('<tr class="x-grid3-subtable-outertable-row"><td><table cellspacing="0" id="subtable-{values.id}" cellpadding="0" class="x-grid3-row-subtable"><tr class="x-grid3-row x-grid3-subtable-row-alt">');

for(var i = 1; i < cols.length; i++){


if (i == 1) {
padding = '';
} else {
padding = '';
}

colWidth = cols[i].width;
template.push('<td class="x-grid3-col x-grid3-cell x-grid3-td-'+cols[i].name+'" style="width: '+colWidth+'px;"><div style="'+padding+'" unselectable="on" id="subfield-{values.id}-'+cols[i].name+'" class="x-grid3-cell-subtablerow x-grid3-cell-inner x-grid3-col-'+cols[i].name+'">' + '{values.data.' + cols[i].name + '}</div></td>');
}

template.push('</tr>');
template.push('</table></td></tr></tpl></table>');

this.tpl = new Ext.XTemplate(template);

if(this.tpl){
if(typeof this.tpl == 'string'){
this.tpl = new Ext.Template(this.tpl);
}
this.tpl.compile();
}

return;

},
processRenderMethod: function (records) {
var cols = this.getActivatedGridColumns();

for (var i=0;i<records.records.length;i++) {
for(var j = 1; j< cols.length; j++){
records.records[i].data[cols[j].name] = cols[j].renderer(records.records[i].data[cols[j].name],
{},
records.records[i]);
}
}

return records;
},
getBodyContent : function(record, index){
records = record.subdata;

var body = "";

if (records.records.length > 0) {
body = this.tpl.apply(records.records);
}
this.bodyContent[record.id] = body;

return body;
}
});

jay@moduscreate.com
24 Mar 2008, 8:45 AM
i like it. i also like how you give copyright over to ext for the code ;)

timo.nuros
24 Mar 2008, 8:53 AM
It's because these files are from the example, and I didn't remove the copyright notice. License for my extension is as-is.

Shaguar
24 Mar 2008, 9:00 AM
Can you please post a comment how to use this plugin with MySQL and JSON/PHP to fill the grid instead of using a fix array of data?
That would be awesome!
Thx.

timo.nuros
24 Mar 2008, 9:11 AM
1. Fill the grid using JSON like you would usually do.
2. Specify "reader" : "json" in the config (see above).

Shaguar
24 Mar 2008, 10:42 AM
Thx, another question:
How can i hide the expander icon "+" if the row doesnt have any sub entries?

timo.nuros
24 Mar 2008, 10:44 AM
Thx, another question:
How can i hide the expander icon "+" if the row doesnt have any sub entries?

Not possible at the moment. Feel free to contribute a patch.

Timo

vk214
2 Apr 2008, 7:15 AM
Timo, this is a great extension! One question, would your extension for the Row Expander work for an XML reader? I'm getting data from the back-end in XML format, not in JSON Array format. I was thinking of adding a 'subdata' node in my tree of data; but not sure how to implement your extension with this...

Thanks in advance.

timo.nuros
2 Apr 2008, 7:30 AM
Have a look at the source; there's a location where a JsonReader is created. Add your reader to that and give it a try. I didn't add it because I never used XMLReader.

Regards,
Timo

vk214
2 Apr 2008, 10:18 AM
I'm a bit of a beginner, so this question may seem trivial - But, in your sample code, you have:


var expander = new Ext.ux.SubTableRowExpander({
subdata: 'subdata',
reader: 'array'
});


In my case, what would take the place of 'array' ? Is that the type of reader you are using? I've tried 'xml' or 'xmlReader' but neither seem to work.

Also, maybe you can point me to where the reader is defined in the source code, I can't seem to find it? Did you mean to look in RowExpander.js, and your extension code?

Thanks...

timo.nuros
3 Apr 2008, 7:49 AM
My extension doesn't support xmlReader. You have to add it to my extension code.

Regards,
Timo

vk214
3 Apr 2008, 9:24 AM
Hi Timo,
Thanks...I know you had mentioned earlier that you didn't support xml. Can you give me some guidance on where you use the 'reader' parameter in your function call? I see you passing it to the super class, but I'm not sure how it's actually being used. I'd like to add to it, but am hoping for a bit of direction on where to look to do so...

timo.nuros
4 Apr 2008, 3:01 PM
Look for the switch statement. You have to figure out the rest on your own. Sorry can't give more free support on that.

cheers,
Timo

vk214
7 Apr 2008, 5:49 AM
I must be looking at the wrong code, because there is no "switch" statement that I can see.

I'm sorry you got the wrong idea - I'm not trying to get 'free support'. Rather I post these questions b/c I thought this was an online community that could help me get up to speed with this new library. The questions I ask may seem trivial to you, but being completely new to Ext (just saw it a couple weeks ago), I'm still trying to wrap my hands around some topics. I was trying to create a POC for my boss to convince him to use this *very cool* library rather than another library he is looking at, which does all of these things out of the box.

Thanks anyway for your help.

timo.nuros
7 Apr 2008, 8:27 AM
I see a switch statement. I posted only 2 pieces of code, one example, one plugin code. It's not hard to find it when you copy the code to a text editor and search for "switch". Maybe I didn't make it clear:

This extension is by me and I am NOT from the Ext team. Thus, I cannot give you free support. I work for customers, thus everytime I do anything in this forum is business related. You requested to extend my code (which doesn't belong to Ext itself) with something it doesn't do, so you have to take your time and learn JS, Ext and the internals and follow my hints (which you definitely ignored, because it is not too hard to find the switch statement) or pay me to implement it.

cheers,
Timo

vk214
7 Apr 2008, 9:21 AM
I understand that you are not part of the core Ext team, and I do appreciate that you put out an extension for the community to see. To clarify, I was never asking you to implement this for me, I am willing to learn on my own, I had only asked for some guidance from you. I don't appreciate your presumption otherwise.
Your code that I had gotten from this post was different when I copied it. I'm not sure if you've changed the code recently or if I somehow copied/pasted wrong, but I did not get the "createSubData" method.

This is the code I saw:

//Extension for Expander
Ext.grid.SubTableRowExpander = function(config){
if (!config.subdata) { config.subdata = 'subdata'; }
Ext.apply(this, config);

Ext.grid.SubTableRowExpander.superclass.constructor.call(this);

this.state = {};
this.bodyContent = {};

};

Ext.extend(Ext.grid.SubTableRowExpander, Ext.grid.RowExpander, {
enableCaching: false,

init: function (grid) {

var ret = Ext.grid.SubTableRowExpander.superclass.init.call(this, grid);

this.grid.view.afterMethod('onColumnHiddenUpdated', this.reconfigureTemplate, this);
this.grid.view.afterMethod('onLayout', this.reconfigureTemplate, this);
this.grid.view.afterMethod('onColumnWidthUpdated', this.doWidth, this);
this.grid.view.afterMethod('onAllColumnWidthsUpdated', this.doAllWidths, this);
this.grid.view.afterMethod('afterMove', this.doAllWidths, this);


},
doWidth: function () {
this.reconfigureTemplate();
this.updateRows();
},
updateRow: function (row) {
var record = this.grid.store.getAt(row);

if(typeof row == 'number'){
row = this.grid.view.getRow(row);
}

var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);

var records = this.grid.store.reader.readRecords(record.data[this.subdata]);

records = this.processRenderMethod(records);

var content = this.tpl.apply(records.records);

this.bodyContent[record.id] = content;
body.innerHTML = content;
},
updateRows: function () {
var ns = this.grid.view.getRows();
for(var i = 0, len = ns.length; i < len; i++){
this.updateRow(i);
}
},
doAllWidths: function () {
this.reconfigureTemplate();
this.updateRows();
},
getActivatedGridColumns: function () {
var cm = this.grid.view.cm;

var cols = [];

for(var i = 0; i < cm.getColumnCount(); i++){
if (!cm.isHidden(i)) {
var col = {};
var name = cm.getDataIndex(i);
col.name = (typeof name == 'undefined' ? this.ds.fields.get(i).name : name);
col.index = i;
col.width = this.getColumnWidth(i);
col.renderer = cm.getRenderer(i);
cols.push(col);
}
}

return cols;
},
getColumnWidth : function(col){
var w = this.grid.view.cm.getColumnWidth(col);
if(typeof w == 'number'){
w = (Ext.isBorderBox ? w : (w-this.grid.view.borderWidth > 0 ? w-this.grid.view.borderWidth:0));
}

return w;
},

reconfigureTemplate: function () {
var cols = this.getActivatedGridColumns();

var template = [
'<table cellspacing="0" cellpadding="0" class="x-grid3-row-table">',
'<tpl for=".">'
];

template.push('<tr class="x-grid3-row-alt">');

var padding, colWidth;

for(var i = 1; i < cols.length; i++){
if (i == 1) {
padding = 'padding-left: 10px;';
} else {
padding = '';
}

colWidth = cols[i].width;

template.push('<td class="x-grid3-col x-grid3-cell x-grid3-td-'+cols[i].name+'" style="width: '+colWidth+'px;"><div style="'+padding+'" class="x-grid3-cell-inner x-grid3-col-'+cols[i].name+'">' + '{values.data.' + cols[i].name + '}</div></td>');

}

template.push('</tr>');
template.push('</tpl>');
template.push('</table>');


this.tpl = new Ext.XTemplate(template);

if(this.tpl){
if(typeof this.tpl == 'string'){
this.tpl = new Ext.Template(this.tpl);
}
this.tpl.compile();
}

return;

},
processRenderMethod: function (records) {
var cols = this.getActivatedGridColumns();

for (var i=0;i<records.records.length;i++) {
for(var j = 1; j< cols.length; j++){
records.records[i].data[cols[j].name] = cols[j].renderer(records.records[i].data[cols[j].name]);
}
}

return records;
},
getBodyContent : function(record, index){
var records = this.grid.store.reader.readRecords(record.data[this.subdata]);

records = this.processRenderMethod(records);

body = this.tpl.apply(records.records);
this.bodyContent[record.id] = body;
return body;
}
});

As you can see, there is no switch statement, and there really isn't a place in this code where you specify the reader as "array" or "json". That's why I was having a tough time and asked for your guidance.

timo.nuros
7 Apr 2008, 12:03 PM
Thats strange, because I posted the updated example and code at the same time (because at the time I introduced the "reader" property in the sample, I already had done that in the plugin code. Probably there went something wrong when you copied it. Could you implement the XmlReader? As I said, I never used it before, and thus I have no clue if it is compatible with my Plugin at all.

By the way, if this plugin is an absolute requirement for your evaluation, you better stick to the other product you mentioned since this is not a base component of Ext - which also means that if there will be a Version 3 of Ext, it is unlikely that I port this thing to the next version (but I plan to maintain it for my customer for the 2.x cycle).

cheers,
Timo

jelt
16 Apr 2008, 7:12 AM
Hi all,

Thank you timo for your shared code, it's geat =D>

To hide the expander (+) when there is no subdata, patch the plugin like this :

line 196, replace :


renderer : function(v, p, record){
p.cellAttr = 'rowspan="2"';
return '<div class="x-grid3-row-expander"> </div>';
},
With :


renderer : function(v, p, record){
p.cellAttr = 'rowspan="2"';
if ((record.subdata) && (record.subdata.totalRecords) && (record.subdata.totalRecords>0)) {
return '<div class="x-grid3-row-expander"> </div>';
} else {
return '';
}
},
Feel free to add a config parameter to choose if you want to display useless expander or not ;)

Oh, and i just found a little bug (FF2 & IE6).
In normal use of the plugin subline is not highlightable, OK
But after you clicked one time on a sub-cell, if you put the mouse over the CELL you have previously clicked, sub line is highlighted !!
This strange behavious occurs only on the clicked cells of the sub lines.


Edit : I just found why ! The inner DIV you used have no ID. When you click on a cell, ext generate id for the div, then the sub line become highlightable.

Edit 2 : previous code written have issue if no one subdata is given for the grid (of for the current page of a paging)

BrunoG
16 Apr 2008, 8:59 AM
Use the following 'renderer' function of Ext.ux.SubTableRowExpander:


renderer : function(v, p, record){
p.cellAttr = 'rowspan="2"';
if(record.data.subdata.length > 0) {
return '<div class="x-grid3-row-expander"> </div>';
} else {
return '';
}

jelt
16 Apr 2008, 11:50 PM
Hi,

To fix the pervious bug i reported (sub line not highlighted), just apply this :

find (line 36x):

template.push('<td class="x-grid3-col x-grid3-cell x-grid3-td-'+cols[i].name+'" style="width: '+colWidth+'px;"><div style="'+padding+'" unselectable="on" class="x-grid3-cell-subtablerow x-grid3-cell-inner x-grid3-col-'+cols[i].name+'">' + '{values.data.' + cols[i].name + '}</div></td>');

and replace by :

template.push('<td class="x-grid3-col x-grid3-cell x-grid3-td-'+cols[i].name+'" style="width: '+colWidth+'px;"><div style="'+padding+'" unselectable="on" id="subfield-{values.id}-'+cols[i].name+'" class="x-grid3-cell-subtablerow x-grid3-cell-inner x-grid3-col-'+cols[i].name+'">' + '{values.data.' + cols[i].name + '}</div></td>');

jelt
17 Apr 2008, 12:10 AM
Use the following 'renderer' function of Ext.ux.SubTableRowExpander:


renderer : function(v, p, record){
p.cellAttr = 'rowspan="2"';
if(record.data.subdata.length > 0) {
return '<div class="x-grid3-row-expander"> </div>';
} else {
return '';
}


Your proposal hardcode the name of the field used for "subdata"

timo.nuros
24 Apr 2008, 10:19 AM
I added Jelt's patch for the highlighting problem. I could not add BunoG's function because it didn't work and I couldn't figure out why.

cheers,
Timo

jelt
25 Apr 2008, 12:34 AM
I could not add BunoG's function because it didn't work and I couldn't figure out why.

Have you tried this ? http://www.extjs.com/forum/showthread.php?p=153938#post153938
Similar to BrunoG's function, but work ;)

timo.nuros
25 Apr 2008, 2:59 AM
Yes, I also tried that. The problem was that all handlers (+) were gone, no matter if there was subdata or not.

jelt
25 Apr 2008, 3:10 AM
you have 2 render function in your plugin, have you tried to replace both ?

I replace only the second and it work in my case (IE6 & FF2)

nanich
28 Apr 2008, 10:06 PM
Sub data having still subrows doesn't seems to be working. can anybody help me out in solving this problem.

Thanks in advance.

timo.nuros
29 Apr 2008, 2:50 AM
nanich, if I understood you correctly: Only one level is supported. For everything else, you have to stick with a tree. Hint to the ExtJS guys: Seems that a multi-level tree control with rows and sorting seems to be a popular request ;)

yeryer
12 May 2008, 4:52 AM
1. Fill the grid using JSON like you would usually do.
2. Specify "reader" : "json" in the config (see above).


For anyone interested in downloading the subdata on-demand via ajax/JSON one way is to change the expand handler around line 169. I changed the function to take 4 parameters, the fourth being the rowIndex and added an Ext.Ajax.request to my server. The success method calls subtableRowExpander.updateRow(rowIndex) to immediately render the subtable. So the initial page load includes an empty array for each row's subdata attribute and when the row is expanded the actual data is requested.

s_kumar
13 May 2008, 10:04 PM
hi,
it's really nice plugin and suits me requirement.
right now i am generating simple grid using DWRProxy and JsonReader.
can you please suggest me how to use your plugin with DWRProxy. Because my data is coming from Java side.Response object is like Collection object inside object.

knarz
14 May 2008, 4:46 AM
I get some strange Errors when using the expander:

syntax error: chrome://firebug/content/blank.gif"" unselectable="on" id="subfield-'+(values.id === undefined ? '' : values.id)+'... ext-all-debug.js (line 6958)


syntax error: chrome://firebug/content/blank.gif"" unselectable="on" id="subfield-'+(values.id === undefined ? '' : values.id)+'... ext-all-debug.js (line 6958)

cheema
23 Jun 2008, 12:01 PM
Does this new and update plugin work for anybody. I can get the older version here in a different thread to work without problems.

http://extjs.com/forum/showthread.php?p=185704

However this newer one gives me the following error in firebug:

"fn has no properties" on line 1317 in ext-all-debug.js.
if((v = fn.apply(scope || obj, args)) !== undefined){ ...

I would debug this but for some reason Firebug is refusing to jump into Ext's source for me. So I cannot put break points or follow executing to try and figure out where the problem may be.

Also I have tried this with both Ext 2.0.2 and the current 2.1. Same error.

Can someone post a complete example as an attachment (to avoid any cut and paste errors from poster or reader)? I am dying to figure out why it does not work for me.

cheema
23 Jun 2008, 3:23 PM
Please ignore this message. The problem did turn out to be a cut and paste error on my part. Spent a few hours trying to figure that out. I would like to request that all plugins be distributed as file attachments to avoid this sort of problems.

Thanks for a great plugin BTW.


Does this new and update plugin work for anybody. I can get the older version here in a different thread to work without problems.

http://extjs.com/forum/showthread.php?p=185704

However this newer one gives me the following error in firebug:

"fn has no properties" on line 1317 in ext-all-debug.js.
if((v = fn.apply(scope || obj, args)) !== undefined){ ...

I would debug this but for some reason Firebug is refusing to jump into Ext's source for me. So I cannot put break points or follow executing to try and figure out where the problem may be.

Also I have tried this with both Ext 2.0.2 and the current 2.1. Same error.

Can someone post a complete example as an attachment (to avoid any cut and paste errors from poster or reader)? I am dying to figure out why it does not work for me.

Anitha
12 Jul 2008, 1:42 AM
Thanks for sharing this Row Expander plugin. Please help me resolving row expander with nested rows expanding.

Thanks in advance.

timo.nuros
12 Jul 2008, 5:53 PM
If you mean a tree-like grid by "nested" rows - sorry, it's not possible.

rtconner
23 Aug 2008, 6:19 PM
If I use a renderer for a column, how do I get it to apply to the subrow's column?

mjlecomte
23 Aug 2008, 6:43 PM
If I use a renderer for a column, how do I get it to apply to the subrow's column?

I think this is in Grid FAQ.

abhipriya
27 Aug 2008, 9:51 PM
Hi All,

I have two separate EditorGridPanels, one parent another child.
What I am trying to achieve is that,when I add a new row for parent & click on '+', the child panel should be displayed with-in that.

The code is -


Ext.onReady(function(){
Ext.QuickTips.init();
var fm = Ext.form;
////////////////////////////////////////////////////////////////////////////////////////
// COMPONENT GRID //
////////////////////////////////////////////////////////////////////////////////////////

var expander = new Ext.grid.RowExpander({
tpl : new Ext.Template(
'<p><b>Bring JMS Queue ACL panel here</b>',
'<div id="JMSQueueAcl"></div>'
)
});
var componentModel = new Ext.grid.ColumnModel([
expander,
{
id:'name',
header: "Name",
dataIndex: 'name',
width: 150,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Description",
dataIndex: 'descr',
width: 150,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Max Bytes",
dataIndex: 'maxbytes',
width: 150,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Exclusive",
dataIndex: 'exclusive',
width: 150,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Prefetch",
dataIndex: 'pfetch',
width: 150,
editor: new fm.TextField({
allowBlank: false
})
}
]);
// by default columns are sortable
componentModel.defaultSortable = true;
var JMSQueue = Ext.data.Record.create([
{name: 'name', type: 'string'},
{name: 'descr', type: 'string'},
{name: 'maxbytes', type: 'string'},
{name: 'exclusive', type: 'string'},
{name: 'pfetch', type: 'string'}
]);
// create the Data Store for Component
var store = new Ext.data.Store({
// the return will be XML, so lets set up a reader
reader: new Ext.data.XmlReader({
// records will have a "plant" tag
record: 'plant'
}, JMSQueue),
sortInfo:{field:'name', direction:'ASC'}
});
var smComponent = new Ext.grid.RowSelectionModel({ });
var componentGrid = new Ext.grid.EditorGridPanel({
store: store,
cm: componentModel,
sm: smComponent,
renderTo: 'JMSQueue',
width:800,
height:300,
title:'JMS Queue',
frame:true,
plugins: expander,
clicksToEdit:1,

tbar:[{
text:'Add',
iconCls:'add',
tooltip:'Add a new JMS Queue',
handler : function(){
var p = new JMSQueue({
name: 'Queue1',
descr:'Queue1 Desc',
maxbytes: '10000',
exclusive: 'mmx',
pfetch: 'mmx'
});
componentGrid.stopEditing();
store.insert(0, p);
componentGrid.startEditing(0, 0);
}
}, '-', {
text:'Remove',
tooltip:'Remove selected JMS Queue',
iconCls:'remove',
handler : function(){
var selected = componentGrid.getSelectionModel().getSelections();
if(selected.length > 0)
{
Ext.Msg.show({
title:'Confirm?',
msg: 'Are you sure you want to delete the selected row?',
buttons: Ext.Msg.OKCANCEL,
fn: function(btn){
if (btn == 'ok'){
for(var i=0;i<selected.length;i++)
{
store.remove(selected[i]);
}
}
}
});
}
}
}]
});

////////////////////////////////////////////////////////////////////////////////////////
// SUB-COMPONENT GRID //
////////////////////////////////////////////////////////////////////////////////////////

var subCompExpander = new Ext.grid.RowExpander({
tpl : new Ext.Template(
'<p><b>Item1</b><br>'
)
});

var JMSQueueACL = Ext.data.Record.create([
// the "name" below matches the tag name to read, except "availDate"
// which is mapped to the tag "availability"
{name: 'uname', type: 'string'},
{name: 'send', type: 'string'},
{name: 'receive', type: 'string'},
{name: 'browse', type: 'string'},
{name: 'receive', type: 'string'},
{name: 'durable', type: 'string'},
{name: 'transactional', type: 'string'}
]);
var subCompStore = new Ext.data.Store({
// the return will be XML, so lets set up a reader
reader: new Ext.data.XmlReader({
// records will have a "plant" tag
record: 'plant'
}, JMSQueueACL),
sortInfo:{field:'uname', direction:'ASC'}
});
// create the editor grid
var subComponentModel = new Ext.grid.ColumnModel([
subCompExpander,
{
id:'uname',
header: "User/Group",
dataIndex: 'uname',
width: 80,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Send",
dataIndex: 'send',
width: 80,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Receive",
dataIndex: 'receive',
width: 80,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Browse",
dataIndex: 'browse',
width: 80,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Durable",
dataIndex: 'durable',
width: 80,
editor: new fm.TextField({
allowBlank: false
})
},{
header: "Transactional",
dataIndex: 'transactional',
width: 80,
editor: new fm.TextField({
allowBlank: false
})
}
]);
subComponentModel.defaultSortable = true;
var smSubComponent = new Ext.grid.RowSelectionModel({ });
var subComponentGrid = new Ext.grid.EditorGridPanel({
store: subCompStore,
cm: subComponentModel,
sm: smSubComponent,
renderTo: 'JMSQueueAcl',
width:520,
height:200,
title:'JMS Queue ACL',
frame:true,
plugins: subCompExpander,
clicksToEdit:1,
tbar:[{
text:'Add',
iconCls:'add',
tooltip:'Add a new JMS Queue',
handler : function(){
var p = new JMSQueueACL({
uname: 'Queue1 ACL1',
send: 'mmx-send1',
receive: 'mmx-receive1',
browse: 'mmx-browser1',
durable: 'durable1',
transactional: 'tran1'
});
subComponentGrid.stopEditing();
subCompStore.insert(0, p);
subComponentGrid.startEditing(0, 0);
}
}, '-', {
text:'Remove',
tooltip:'Remove the selected item',
iconCls:'remove',
handler : function(){
var selected = subComponentGrid.getSelectionModel().getSelections();
if(selected.length > 0)
{
Ext.Msg.show({
title:'Confirm?',
msg: 'Are you sure you want to delete the selected row?',
buttons: Ext.Msg.OKCANCEL,
fn: function(btn){
if (btn == 'ok'){
for(var i=0;i<selected.length;i++)
{
subCompStore.remove(selected[i]);
}
}
}
});
}
}
}]
});
});


As you can see, I am trying to get this by adding a <div> in


var expander = new Ext.grid.RowExpander({
tpl : new Ext.Template(
'<p><b>Bring JMS Queue ACL panel here</b>',
'<div id="JMSQueueAcl"></div>'
)
});

Can someone help me out.

Abhi

sseema
19 Jan 2009, 9:05 PM
Hi...

SubTableRowExpander plugin is so good.
I added that one in my application.
But I am facing one issue .

Can you please give me json java code for that one.

Beacause subdata returns all records i dont know how to restrict that one.

Please give me....

Thank You..

sseema
28 Jan 2009, 11:24 PM
Now this issue is resolved.Its working fine now.
But I am facing another issue..That is I applied drag and drop for that grid.
Its working fine for parent record, but it is not working for sub record.
Actually subrecord is not selected.If I can apply sm(row selection model) feature to subrecords then it ll work fine.

But I dont know how to add that feature to subTableRowExpander plugin.

please tell me how to add that one.

And also If any one knows how to add drag and drop feature to that sub records please tell me.

Thank You.

arajapandi
6 Feb 2009, 1:55 AM
Hi

am using jsonreader for this rowexpander plugin but my data is not displaying in the grid.

below is my code ...........help me to fix....

my Grid Panel

Ext.onReady(function(){

Ext.QuickTips.init();

var xg = Ext.grid;

// shared reader
var reader = new Ext.data.JsonReader({root:'data'}, [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'},
{name: 'industry'},
{name: 'subdata'},
{name: 'desc'}

]);

////////////////////////////////////////////////////////////////////////////////////////
// Grid 1
////////////////////////////////////////////////////////////////////////////////////////
// row expander
var expander = new Ext.ux.SubTableRowExpander({
subdata: 'subdata',
reader: 'json'
});

expander.on("subdblclick", function (r) { alert(r.data.company); });

var store = new Ext.data.JsonStore({
autoLoad:true,
url: 'page.php',
reader: reader
});

var grid1 = new xg.GridPanel({
store: store,
cm: new xg.ColumnModel([
expander,
{id:'company',header: "Company", width: 40, sortable: true, dataIndex: 'company'},
{header: "Price", width: 20, sortable: true, renderer: Ext.util.Format.usMoney, dataIndex: 'price'},
{header: "Change", width: 20, sortable: true, dataIndex: 'change'},
{header: "% Change", width: 20, sortable: true, dataIndex: 'pctChange'},
{header: "Last Updated", width: 20, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
]),
viewConfig: {
forceFit:true
},
width: 600,
height: 300,
plugins: expander,
collapsible: true,
animCollapse: false,
title: 'Expander Rows, Collapse and Force Fit',
iconCls: 'icon-grid',
renderTo: document.body
});

});
json response

{"metaData":{"data":[{"company":"3m Co","price":71.72,"change":0.02,"pctChange":0.03,"lastChange":"9
\/1 12:00am","industry":"Manufacturing","subdata":[{"company":"Alcoa Inc","price":29.01,"change":0.42
,"pctChange":1.47,"lastChange":"9\/1 12:00am","industry":"Manufacturing"},{"company":"AT&T Inc.","price"
:31.61,"change":-0.48,"pctChange":-1.54,"lastChange":"9\/1 12:00am","industry":"Services"},{"company"
:"E.I. du Pont de Nemours and Company","price":40.48,"change":0.51,"pctChange":1.28,"lastChange":"9\
/1 12:00am","industry":"Manufacturing"}]},{"company":"Alcoa Inc","price":29.01,"change":0.42,"pctChange"
:1.47,"lastChange":"9\/1 12:00am","industry":"Manufacturing","subdata":[{"company":"Alcoa Inc","price"
:29.01,"change":0.42,"pctChange":1.47,"lastChange":"9\/1 12:00am","industry":"Manufacturing"},{"company"
:"AT&T Inc.","price":31.61,"change":-0.48,"pctChange":-1.54,"lastChange":"9\/1 12:00am","industry":"Services"
},{"company":"E.I. du Pont de Nemours and Company","price":40.48,"change":0.51,"pctChange":1.28,"lastChange"
:"9\/1 12:00am","industry":"Manufacturing"}]},{"company":"Altria Group Inc","price":83.81,"change":0
.28,"pctChange":0.34,"lastChange":"9\/1 12:00am","industry":"Manufacturing","subdata":[{"company":"Alcoa
Inc","price":29.01,"change":0.42,"pctChange":1.47,"lastChange":"9\/1 12:00am","industry":"Manufacturing"
},{"company":"AT&T Inc.","price":31.61,"change":-0.48,"pctChange":-1.54,"lastChange":"9\/1 12:00am","industry"
:"Services"},{"company":"E.I. du Pont de Nemours and Company","price":40.48,"change":0.51,"pctChange"
:1.28,"lastChange":"9\/1 12:00am","industry":"Manufacturing"}]},{"company":"American Express Company"
,"price":52.55,"change":0.01,"pctChange":0.02,"lastChange":"9\/1 12:00am","industry":"Finance","subdata"
:[{"company":"Alcoa Inc","price":29.01,"change":0.42,"pctChange":1.47,"lastChange":"9\/1 12:00am","industry"
:"Manufacturing"},{"company":"AT&T Inc.","price":31.61,"change":-0.48,"pctChange":-1.54,"lastChange"
:"9\/1 12:00am","industry":"Services"},{"company":"E.I. du Pont de Nemours and Company","price":40.48
,"change":0.51,"pctChange":1.28,"lastChange":"9\/1 12:00am","industry":"Manufacturing"}]}]}}

arajapandi
6 Feb 2009, 3:32 AM
Hi

json response aligned property....


{"metaData":
{"data":
[{"company":"3m Co","price":71.72,"change":0.02,"pctChange":0.03,"lastChange":"9\/1 12:00am","industry":"Manufacturing","subdata":
[{"company":"Alcoa Inc","price":29.01,"change":0.42,"pctChange":1.47,"lastChange":"9\/1 12:00am","industry":"Manufacturing"},
{"company":"AT&T Inc.","price":31.61,"change":-0.48,"pctChange":-1.54,"lastChange":"9\/1 12:00am","industry":"Services"},
{"company":"E.I. du Pont de Nemours and Company","price":40.48,"change":0.51,"pctChange":1.28,"lastChange":"9\/1 12:00am","industry":"Manufacturing"}
]
},
{"company":"Alcoa Inc","price":29.01,"change":0.42,"pctChange":1.47,"lastChange":"9\/1 12:00am","industry":"Manufacturing","subdata":
[{"company":"Alcoa Inc","price":29.01,"change":0.42,"pctChange":1.47,"lastChange":"9\/1 12:00am","industry":"Manufacturing"},
{"company":"AT&T Inc.","price":31.61,"change":-0.48,"pctChange":-1.54,"lastChange":"9\/1 12:00am","industry":"Services"},
{"company":"E.I. du Pont de Nemours and Company","price":40.48,"change":0.51,"pctChange":1.28,"lastChange":"9\/1 12:00am","industry":"Manufacturing"}
]
},
{"company":"Altria Group Inc","price":83.81,"change":0.28,"pctChange":0.34,"lastChange":"9\/1 12:00am","industry":"Manufacturing","subdata":
[{"company":"Alcoa Inc","price":29.01,"change":0.42,"pctChange":1.47,"lastChange":"9\/1 12:00am","industry":"Manufacturing"},
{"company":"AT&T Inc.","price":31.61,"change":-0.48,"pctChange":-1.54,"lastChange":"9\/1 12:00am","industry":"Services"},
{"company":"E.I. du Pont de Nemours and Company","price":40.48,"change":0.51,"pctChange":1.28,"lastChange":"9\/1 12:00am","industry":"Manufacturing"}
]
},
{"company":"American Express Company","price":52.55,"change":0.01,"pctChange":0.02,"lastChange":"9\/1 12:00am","industry":"Finance","subdata":
[{"company":"Alcoa Inc","price":29.01,"change":0.42,"pctChange":1.47,"lastChange":"9\/1 12:00am","industry":"Manufacturing"},
{"company":"AT&T Inc.","price":31.61,"change":-0.48,"pctChange":-1.54,"lastChange":"9\/1 12:00am","industry":"Services"},
{"company":"E.I. du Pont de Nemours and Company","price":40.48,"change":0.51,"pctChange":1.28,"lastChange":"9\/1 12:00am","industry":"Manufacturing"}
]
}
]
}
}

arajapandi
8 Feb 2009, 11:55 PM
Hi,

i figured out the json problem....now its working.

Thanks for no response....

working code is below.....



Ext.onReady(function(){

var proxy=new Ext.data.HttpProxy({url:'page.php'});

var reader=new Ext.data.JsonReader( {
root: 'data',},[
{name: 'appeId', mapping: 'appeId'},
{name: 'survId'},
{name: 'location'},
{name: 'surveyDate'},
{name: 'surveyTime'},
{name: 'subdata'},
{name: 'inputUserId'}
]
)

var store=new Ext.data.Store( {
proxy:proxy,


autoLoad:true,
reader:reader
});

//store.load();

var expander = new Ext.ux.SubTableRowExpander({
subdata: 'subdata',
reader: 'json'
});

expander.on("subdblclick", function (r) { alert(r.data.company); });

var grid = new Ext.grid.GridPanel({
store: store,
columns: [
expander,
{header: "appeId", width: 60, dataIndex: 'appeId', sortable: true},
{header: "survId", width: 60, dataIndex: 'survId', sortable: true},
{header: "location", width: 60, dataIndex: 'location', sortable: true},
{header: "surveyDate", width: 100, dataIndex: 'surveyDate', sortable: true},
{header: "surveyTime", width: 100, dataIndex: 'surveyTime', sortable: true},
{header: "inputUserId", width:80, dataIndex: 'inputUserId', sortable: true}
],
viewConfig: {forceFit:true},
width: 600,
height: 300,
plugins: expander,
collapsible: true,
animCollapse: false,
renderTo:document.body,

width:540,
height:200
});

});

<?
$arrays = array(
array("appeId"=>"1","survId"=>"1","location"=>"","surveyDate"=>"2008-03-14","surveyTime"=>"12=>19=>47","inputUserId"=>"1","inputTime"=>"2008-03-14 12=>21=>51","modifyTime"=>"0000-00-00 00=>00=>00",
'subdata' => array(array("appeId"=>"1","survId"=>"1","location"=>"","surveyDate"=>"2008-03-14","surveyTime"=>"12=>19=>47","inputUserId"=>"1","inputTime"=>"2008-03-14 12=>21=>51","modifyTime"=>"0000-00-00 00=>00=>00"))
),
array("appeId"=>"2","survId"=>"32","location"=>"","surveyDate"=>"2008-03-14","surveyTime"=>"22=>43=>09","inputUserId"=>"32","inputTime"=>"2008-03-14 22=>43=>37","modifyTime"=>"0000-00-00 00=>00=>00"),
array("appeId"=>"3","survId"=>"32","location"=>"","surveyDate"=>"2008-03-15","surveyTime"=>"07=>59=>33","inputUserId"=>"32","inputTime"=>"2008-03-15 08=>00=>44","modifyTime"=>"0000-00-00 00=>00=>00"),
array("appeId"=>"4","survId"=>"1","location"=>"","surveyDate"=>"2008-03-15","surveyTime"=>"10=>45=>42","inputUserId"=>"1","inputTime"=>"2008-03-15 10=>46=>04","modifyTime"=>"0000-00-00 00=>00=>00"),
array("appeId"=>"5","survId"=>"32","location"=>"","surveyDate"=>"2008-03-16","surveyTime"=>"08=>04=>49","inputUserId"=>"32","inputTime"=>"2008-03-16 08=>05=>26","modifyTime"=>"0000-00-00 00=>00=>00"),
array("appeId"=>"6","survId"=>"32","location"=>"","surveyDate"=>"2008-03-20","surveyTime"=>"20=>19=>01","inputUserId"=>"32","inputTime"=>"2008-03-20 20=>19=>32","modifyTime"=>"0000-00-00 00=>00=>00")
);
$sarray["data"] = $arrays;
print json_encode($sarray);
exit;

timo.nuros
9 Feb 2009, 12:35 AM
See on the first page:


- I cannot provide support for this one. Feel free to report bugs anyways, maybe I'll fix them - but don't expect that.

adbox
30 Mar 2009, 8:59 AM
Can this plug-in work with editor grids now? Or is there something like it available today elsewhere?

I want to be able to have certain rows expandable and certain rows left alone, as there is nothing to associate with them.

My columns are the same for the child items as they are for the parent items... as required.

thank you.

neurons
29 Jul 2009, 8:52 PM
I am trying to acheive the same subrow expander functionality but i need my grid to be editable . Is there any existing solution for this now ?

MatjazH
1 Sep 2009, 3:41 AM
Use the following 'renderer' function of Ext.ux.SubTableRowExpander:


renderer : function(v, p, record){
p.cellAttr = 'rowspan="2"';
if(record.data.subdata.length > 0) {
return '<div class="x-grid3-row-expander"> </div>';
} else {
return '';
}

without hardcoded subdata field name:

renderer : function(v, p, record){
p.cellAttr = 'rowspan="2"';
if(record.data[this.subdata] && record.data[this.subdata].length > 0) {
return '<div class="x-grid3-row-expander"> </div>';
} else {
return '';
}
},

Bobson
27 Oct 2009, 10:23 AM
To move the expansion column:

Replace line 34x
for (var i = 1; i < cols.length; i++) {with
for (var i = 0; i < cols.length; i++) {
if (cols[i].name == "") continue;

You'll need to modify the CSS to make it actually look good, and make sure all your columns have a name, but it does work.

badgerd
24 Nov 2009, 5:03 PM
Has anyone used this with dynamically called subdata?

I have a subdata JSONStore being called, but undefined is constantly returned instead of the proper subdata because its all happening too quickly.

Is there away to pause the beforeExpand event in such a way to allow the dynamic data to be loaded properly before setting body.innerHTML with the value?

Dave++
22 Jan 2010, 4:33 AM
Firstly, the Ext.ux.SubTableRowExpander plug-in is brilliant work!

However, since upgrading to Ext 3.1.0 my code which uses it has broken and I can't figure out why.:-?

Before I get dirty with Firebug, has anyone else experienced any issues using this in Ext 3.1.0?

sniffer
11 Jun 2010, 6:15 AM
This is nice solution really but does any one tried to use EditorGridPanel inside expanded row of EditorGridPanel component?!

httpftp21
22 Jun 2010, 4:17 AM
i like it. i also like how you give copyright over to ext for the code ;)

The copyright is helpful in the sense, if the version number changes as 3.0 is not compatible with 2.x
It should encouraged

httpftp21
22 Jun 2010, 4:26 AM
Firstly, the Ext.ux.SubTableRowExpander plug-in is brilliant work!

However, since upgrading to Ext 3.1.0 my code which uses it has broken and I can't figure out why.:-?

Before I get dirty with Firebug, has anyone else experienced any issues using this in Ext 3.1.0?


This is because RowExpander.js of 2.x is quite different from 3.0
:)

httpftp21
22 Jun 2010, 4:27 AM
Is it possible to initialize a grid inside the row expander ?
If yes then how is it possible ?

httpftp21
29 Jun 2010, 11:21 PM
Hi
i am making this alive a bit
anyone here to help me out ??

rohan.chandane
20 Aug 2010, 9:04 AM
Hi, any clue how can I use CheckboxSelectionModel with this?

PrashanthShetty
9 Dec 2011, 8:01 PM
Hi,

Can you please let me know if there is a similar plugin available in EXTJS4 Version.

I am a great fan of this plugin as we have implemented one project using the same in EXTJS3, now we are planning to upgrade the same project in EXTJS4, So please let us know if there is a similar plugin available in EXTJS4.

I would request the author of the plugin to assist in same to support the EXTJS4 Version of the same.

Thanks,
Prashanth