Update to STORE based RowExpander
I update your code to use the store reader's id value instead of the literal 'id'
instead of
Code:
beforeExpand: function(record, body, rowIndex){
blah....
}else if(this.store && this.tpl && this.lazyRender){
blah... blah...
this.store.load({params: {id: record.id}});
..i do this...
Code:
beforeExpand: function(record, body, rowIndex){
blah....
}else if(this.store && this.tpl && this.lazyRender){
blah... blah...
var params = {};
params[this.store.reader.meta.id] = record.id;
this.store.load({params: params});
Perhaps there is a cleaner way to get the store's reader and its properties?
Ext fields as content of expanded row
Quote:
Originally Posted by
ricardolowe
Only solution that comes to mind is to pass the datastore for a combobox and do <tpl for loop> over the data to build an HTML dropdown ( <select id={parentrow.id} > ), etc. That feels cheesy for some reason. Would rather use the Ext components.
I needed something similar. My solution is exactly that. In the tpl, I gave <input type=text id="customFIeld-row{rowIndex}-field1" >.
PHP Code:
tpl : new Ext.XTemplate(
// TODO maybe use form.Field.applyTo on these form input items on expand?
'Account Code: <input type="text" id="customField-row{rowIndex}-field1" name="accountCode" value="{accountCode}" /><br>',
'Product Code: <input type="text" id="customField-row{rowIndex}-field2" name="projectCode" value="{projectCode}" />'
)
To get rowIndex I had to change RowExpander.getBodyContent().
PHP Code:
// Also apply rowIndex in addition to record.data.
content = this.tpl.apply( Ext.apply( {rowIndex: index}, record.data ) )
I used the RowExpander with a store provided earlier in this thread.
PHP Code:
expander.on("render", function( pExpander, pRecord, pBody, pRowIndex, pStore, pRecords) {
if ( ! this.expandingPanel ) {
this.expandingPanel = [];
}
this.expandingPanel[pRowIndex] = new Ext.Panel(
{
// title: 'Custom Fields',
layout:'fit',
// monitorResize: true,
// autoDestroy: false,
// height: 300,
items: [
{
xtype: 'textfield',
applyTo: 'customField-row' + pRowIndex + '-field1',
fieldLabel: 'Account Code',
...
I haven't quite worked out how to make the panel look good, that is, use the field labels, but it works for now. Still in progress...
I had gone the Panel.renderTo approach and used a div in the tpl, but the content disappeared after the 2nd expand on each row and the data would be lost.
good job,but i found a bug and fixed it
Hello,everybuddy:
I use the plugin in an pre-configured grid class. I found a bug: when I clicked the expander plugin, the icon changed but not content diplay. I inserted an alert into the remotemethod, I found that the remotemethod had been called. What happened? I check out the source code and maybe found the source of it. I fixed this bug with following code,perhaps it will help somebody.
By the way, I use this plugin by:
Code:
initComponent: function(){
this.expander = new Ext.ux.RowExpander({
remoteDataMethod : this.getExpanderContent
});
Ext.apply(this, {
store: this.ds,
columns: [
this.expander,
............
]
,plugins:[this.cellActions,this.expander]
});
}
/*
* Ext JS Library 2.0
* Copyright(c) 2006-2007, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*
* MODIFIED: SGB [12.12.07]
* Added support for a new config option, remoteDataMethod,
* including getter and setter functions, and minor mods
* to the beforeExpand and expandRow functions
* lisihao: ****,this plugin has some bugs, so can't dispaly content when toggle the row.I fix it.RI!
*/
Ext.ux.RowExpander = function(config){
Ext.apply(this, config);
Ext.ux.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 = {};
this.addEvents({
beforeexpand : true,
expand: true,
beforecollapse: true,
collapse: true
});
};
Ext.extend(Ext.ux.RowExpander, Ext.util.Observable, {
header: "",
width: 20,
sortable: false,
fixed: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;
},
// Setter and Getter methods for the remoteDataMethod property
setRemoteDataMethod : function (fn){
this.remoteDataMethod = fn;
},
getRemoteDataMethod : function (record, index){
if(!this.remoteDataMethod){
return;
}
return this.remoteDataMethod.call(this,record,index);
},
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"> </div>';
},
beforeExpand : function(record, body, rowIndex){
if(this.fireEvent('beforexpand', this, record, body, rowIndex) !== false){
// If remoteDataMethod is defined then we'll need a div, with a unique ID,
// to place the content
if(this.remoteDataMethod){
this.tpl = new Ext.Template("<div id='remData" + rowIndex + "' class='rem-data-expand'><\div>");
}
if(this.tpl && this.lazyRender){
// body.innerHTML = this.getBodyContent(record, rowIndex);
body.innerHTML = '<div id="remData"' + rowIndex + '" class="rem-data-expand">'+this.getRemoteDataMethod(record, rowIndex)+'</div>';// >>>>>--- change here!!!
}
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');
if(this.fireEvent('expand', this, record, body, row.rowIndex) !== false){
// If the expand event is successful then get the remoteDataMethod
this.getRemoteDataMethod(record,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);
}
}
});
thanks, i post the reply in incorrect style. You fix it!
thanks, i post the reply in incorrect style. You fix it!
Ext fields as content of expanded row without Tpl
ricardolowe was asking how to put Ext fields into the expanded row. I had the same requirement. I initially thought I had it solved but found problems. See here now the working solution which allows combo boxes, text boxes, etc in the expanded row content without using a Template. Just override a method to return Ext Panel items. The overridden method has access to the grid.store record of the row OR a record of a store passed in the config parm of RowExpander.
Here's the abstract class:
PHP Code:
/**
* RowExpander changed from RowExpander.js in the Ext examples and some ideas taken
* from the forum (http://extjs.com/forum/showthread.php?t=21017&page=3).
*
* Override the createExpandingRowPanelItems function to make Ext expanded row content
* (as opposed to using Ext.Template to make the expanded row content).
*
* If config.store is passed in, pass a record for the row from that store instead
* of the grid store into the createExpandingRowPanelItems function.
*/
Ext.grid.RowExpander = function(config){
Ext.apply(this, config);
Ext.grid.RowExpander.superclass.constructor.call(this);
this.state = {};
this.addEvents({
beforeexpand : true,
expand: true,
beforecollapse: true,
collapse: true
});
};
Ext.extend(Ext.grid.RowExpander, Ext.util.Observable, {
header: "",
width: 20,
sortable: false,
fixed:true,
dataIndex: '',
id: 'expander',
lazyRender : true,
enableCaching: true,
getRowClass : function(record, rowIndex, rowParams, ds){
// cols: The column count to apply to the body row's TD colspan attribute (defaults to the current column count of the grid).
rowParams.cols = rowParams.cols-1; // make it the width of the whole row
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);
// store
grid.getStore().on("load", function(store, records, options){
Ext.select('div.x-grid3-row-expanded').replaceClass('x-grid3-row-expanded', 'x-grid3-row-collapsed');
this.state = {};
}, this);
this.store.load(); // load here instead of in beforeExpand cuz that would wipe out additions to store
},
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"> </div>';
},
beforeExpand : function(record, rowBody, rowIndex){
var isContinue = true;
if(this.fireEvent('beforeexpand', this, record, rowBody, rowIndex, this.store) !== false){
if(rowBody.innerHTML == '' || !this.enableCaching) {
this.createExpandingRowPanel( record, rowBody, rowIndex );
}
} else {
isContinue = false;
}
return isContinue;
},
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);
// if using additional store passed in config, pass record from it instead of from the grid store
var recordToPass = this.store ? this.store.getAt(row.rowIndex) : record;
var rowBody = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);
if(this.beforeExpand(recordToPass, rowBody, row.rowIndex)){
this.state[record.id] = true;
Ext.fly(row).replaceClass('x-grid3-row-collapsed', 'x-grid3-row-expanded');
this.fireEvent('expand', this, recordToPass, rowBody, row.rowIndex);
}
},
collapseRow : function(row){
if(typeof row == 'number'){
row = this.grid.view.getRow(row);
}
var record = this.grid.store.getAt(row.rowIndex);
// if using additional store passed in config, pass record from it instead of from the grid store
var recordToPass = this.store ? this.store.getAt(row.rowIndex) : record;
var body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true);
if(this.fireEvent('beforcollapse', this, recordToPass, 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, recordToPass, body, row.rowIndex);
}
},
createExpandingRowPanel: function( record, rowBody, rowIndex ) {
// record.id is more stable than rowIndex for panel item's key; rows can be deleted.
var panelItemIndex = record.id;
// var panelItemIndex = rowIndex;
// init array of expanding row panels if not already inited
if ( !this.expandingRowPanel ) {
this.expandingRowPanel = [];
}
// Add a new panel to the row body if not already there
if ( !this.expandingRowPanel[panelItemIndex] ) {
this.expandingRowPanel[panelItemIndex] = new Ext.Panel(
{
// title: 'Custom Fields',
// layout:'fit', // this doesn't put the labels there
border: false,
bodyBorder: false,
layout:'form',
renderTo: rowBody,
items: this.createExpandingRowPanelItems( record, rowIndex )
}
);
}
},
/**
* Override this method to put Ext form items into the expanding row panel.
* @return Array of panel items.
*/
createExpandingRowPanelItems: function( record, rowIndex ) {
var panelItems = [];
return panelItems;
}
});
RowExpander does not get the values from the store
I am using a grid to display the data along with a RowExpander.
When the expand the row it does show the fields but without values which I really want to get to. The other issue is I want to learn how to override the createExpandingRowPanelItems function in the RowExpander class. I dont think I am doing it right.
Code:
// row expander
var expander = new Ext.grid.RowExpander({
store: store,
createExpandingRowPanelItems:
function( record, rowIndex ) {
var panelItems = [{
id: 'form-row'+rowIndex,
columnWidth: 0.4,
xtype: 'fieldset',
labelWidth: 90,
//title:'Company details',
defaults: {width: 140}, // Default config options for child items
defaultType: 'textfield',
autoHeight: true,
bodyStyle: Ext.isIE ? 'padding:0 0 5px 15px;' : 'padding:10px 15px;',
border: false,
style: {
"margin-left": "10px", // when you add custom margin in IE 6...
"margin-right": Ext.isIE6 ? (Ext.isStrict ? "-10px" : "-13px") : "0" // you have to adjust for it somewhere else
},
items: [{
fieldLabel: 'Name',
name: 'barcode'
},{
fieldLabel: 'Price',
name: 'title'
},{
fieldLabel: '% Change',
name: 'author'
},{
xtype: 'datefield',
fieldLabel: 'Last Updated',
name: 'barcode'
}]
}];
return panelItems;
}
});