-
2 May 2008 5:51 AM #11
Great plugin, thanks for sharing!
Extensions:
Ext.ux.DatePickerPlus (Multimonth,Multiselect,...)
Ext.ux.menu.StoreMenu - Ajax Store as menu-item config
Extended Window - Aero Shadows, nested grayscaled modal windows
Ext.MessageBox.promptCombo/promptRadio/promptCheckbox
Ext.ux.plugin.triggerfieldTooltip (for Comboboxes, Datefields...)
Ext.util.MD5
Ext.util.Utf8 (encode/decode)
Ext.util.base64 (encode/decode)
Using:
ExtJS 3.4.1.1/4.2
XPsp3/W7sp1
IE8/9/10
FF 20
Chrome 26
-
2 May 2008 11:49 AM #12
If you are finding this Plugin does not play well with Animal's ExportGridToExcel plugin, please see this thread on my update to his plugin to work properly with this plugin. http://extjs.com/forum/showthread.php?t=32400&page=4
For anyone else who might be confused on how to get this plugin to work properly, follow these directions.
Create a new file and name it GridRowExpander.js, put the following code inside and save it.
Make sure you call your .js file from your index page, something that looks like:Code:/* * 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 */ Ext.grid.RowExpander = function(config){ Ext.apply(this, config); 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 = {}; 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, 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); } 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); } } });
Now, in your GridPanel config options, add the following lines:Code:<script type="text/javascript" src="libs/js/ext/ux/GridRowExpander.js"></script>
Under your columns config add:
It might looks like:Code:expander,
And then add this to the GridPanel config options:Code:columns: [ expander, {header: 'Company', width: 160, sortable: true, dataIndex: 'company'}, {header: 'Price', width: 75, sortable: true, dataIndex: 'price'}, {header: 'Change', width: 75, sortable: true, renderer: change, dataIndex: 'change'}, {header: '% Change', width: 75, sortable: true, renderer: pctChange, dataIndex: 'pctChange'}, {header: 'Last Updated', width: 100, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'} ],
Create the expander variable like this (it can be anywhere in your code, as long as the GridPanel has scope:Code:plugins: expander,
Finally, add your new function, expandGrid anywhere in your code:Code:// Plugin for gridRowExpander which calls data from an external source var expander = new Ext.grid.RowExpander({ remoteDataMethod : expandGrid });
And that should do it! Thanks to the OP for the original plugin code. Cheers!Code:// Remotely populates grid using data function expandGrid(record,index){ Ext.get('remData'+index).load({ url: "your_external_file.html", scripts: true, params: "" }); };Noah
Senior Web Developer
NBA.com
-
6 May 2008 3:46 AM #13
RowExpander upgrade
RowExpander upgrade
This behaviour should be implemented in the RowExpander itself.
At the end of init method in RowExpander add
Code:init : function(grid){ //original code.... 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.bodyContent = {}; }, this);
-
6 May 2008 4:02 AM #14
Hello,
im working with the RowExpander and i m trying to find how to nest two grid inside a master grid like this :
master grid
------------>slave grid
----------------> slave "slave" grid
for the moment i have the following result (grid without headers except the last one)
example.jpg
but the deepest grid has a strange behavior : it does'nt collapse correctly
here is my code :
Code:var dayGrid = function(gridID, title, data){ var xg = Ext.grid; // shared reader var reader = new Ext.data.ArrayReader({}, [ {name: 'id'}, {name: 'day'}, {name: 'quantitytheo', type: 'float'}, {name: 'quantitysettled', type: 'float'} ]); //////////////////////////////////////////////////////////////////////////////////////// // DAY GRID //////////////////////////////////////////////////////////////////////////////////////// // row expander // Issue template // row expander var expander = new Ext.grid.RowExpander({ remoteDataMethod : borrowlendGrid }); var masterGrid = new xg.GridPanel({ ds: new Ext.data.Store({ reader: reader, data: xg.dummyData }), cm: new xg.ColumnModel([ expander, {header: "Day", width: 200, sortable: true, dataIndex: 'day'}, {header: "Theoretical Quantity", width: 200, sortable: true, dataIndex: 'quantitytheo'}, {header: "Settled Quantity", width: 200, sortable: true, dataIndex: 'quantitysettled'} ]), viewConfig: { forceFit:true }, autoHeight: true, hideHeaders: true, width: 800, height: 800, plugins: expander, collapsible: true, animCollapse: false, disableSelection : true, trackMouseOver : false, enableHdMenu : false, renderTo: document.getElementById('testGrid') }); } //////////////////////////////////////////////////////////////////////////////////////// // BORROW LEND GRID //////////////////////////////////////////////////////////////////////////////////////// var borrowlendGrid = function(record, index) { var xg = Ext.grid; var blreader = new Ext.data.ArrayReader({}, [ {name: 'id'}, {name: 'type'}, {name: 'theoQty'}, {name: 'theoQtyValue', type: 'float'}, {name: 'settledQty'}, {name: 'settledQtyValue', type: 'float'} ]); var blstore = new Ext.data.Store({ reader: blreader, data: xg.dummyData2 }); var iexpander = new Ext.grid.RowExpander({ remoteDataMethod : detailedMovementGrid, tpl: new Ext.Template( '<div id="subRemData"></div>') }); var blgrid = new xg.GridPanel({ ds: blstore, cm: new xg.ColumnModel([ iexpander, {header: "Type", width: 200, sortable: true, dataIndex: 'type'}, {header: "Theoretical", width: 80, sortable: true, dataIndex: 'theoQty'}, {header: "Theoretical Quantity", width: 80, sortable: true, dataIndex: 'theoQtyValue'}, {header: "Settled", width: 80, sortable: true, dataIndex: 'settledQty'}, {header: "Settled Quantity", width: 80, sortable: true, dataIndex: 'settledQtyValue'} ]), viewConfig: { forceFit:true }, disableSelection : false, hideHeaders: true, autoHeight: true, plugins: iexpander, collapsible: false, disableSelection : true, enableHdMenu : false, trackMouseOver : false, autoSizeColumns: true }); blgrid.render(Ext.get('remData'+record.data.id)); }; //////////////////////////////////////////////////////////////////////////////////////// // DETAILLED MOVEMENTS GRID //////////////////////////////////////////////////////////////////////////////////////// var detailedMovementGrid = function(record, index) { var id = record.get("code"); var xg = Ext.grid; var detailedreader = new Ext.data.ArrayReader({}, [ {name: 'id'}, {name:'code'}, {name: 'name'}, {name: 'tradeRef'}, {name: 'S'}, {name: 'T'}, {name: 'qty'}, {name: 'start'}, {name: 'end'}, {name: 'loanCcy'}, {name: 'loanValue'}, {name: 'rate'}, {name: 'divReq'} ]); var detailedstore = new Ext.data.Store({ reader: detailedreader, data: xg.dummyData3 }); var detailedgrid = new xg.GridPanel({ ds: detailedstore, cm: new xg.ColumnModel([ {header: 'Client Code', width: 50, sortable: true, dataIndex: 'code'}, {header: 'Client Name', width: 120, sortable: true, dataIndex: 'name'}, {header: 'Trade Ref', width: 50, sortable: true, dataIndex: 'tradeRef'}, {header: 'S', width: 20, sortable: true, dataIndex: 'S'}, {header: 'T', width: 20, sortable: true, dataIndex: 'T'}, {header: 'Quantity', width: 60, sortable: true, dataIndex: 'qty'}, {header: 'Start Date', width: 60, sortable: true, dataIndex: 'start'}, {header: 'End Date', width: 60, sortable: true, dataIndex: 'end'}, {header: 'Loan Ccy', width: 60, sortable: true, dataIndex: 'loanCcy'}, {header: 'Loan Value', width: 60, sortable: true, dataIndex: 'loanValue'}, {header: 'rate', width: 60, sortable: true, dataIndex: 'rate'}, {header: 'Div Req', width: 60, sortable: true, dataIndex: 'divReq'}, ]), viewConfig: { forceFit:true }, autoHeight: true, collapsible: false, disableSelection : true, trackMouseOver : false, autoSizeColumns: true }); detailedgrid.render(Ext.get('remData'+record.data.id)); }; /*** functions ***/ function issueLoad() { Ext.QuickTips.init(); Ext.BLANK_IMAGE_URL = '/static/images/transparentpixel.gif'; new dayGrid("mastergrid", "Host Issues", Ext.grid.dummydata); } Ext.onReady(issueLoad);J2EE/Ajax
-
6 May 2008 5:29 AM #15
-
1 Jun 2008 2:08 AM #16
how to keep row expanded on store reload?? using rowExpander plugin
how to keep row expanded on store reload?? using rowExpander plugin
I am using rowExpander plugin as given in ExtJs examples folder. It is working nicely, but on store reload, all rows become collapsed though some were in expanded state before refresh. how can I keep rows expanded. I saw the code given in above quoted post, but could not get it to work, Please help me!!! Here is simplified version of my code..
Code:var expander = new Ext.grid.RowExpander({ tpl : new Ext.Template('This is a test grid<br>Testing') }); var mystore = new Ext.data.Store({ url: 'plantsdetail.xml', reader: new Ext.data.XmlReader({ record: 'plant' }, [ 'id2','nature','useful' ]) }); mystore.load(); var cm = new Ext.grid.ColumnModel([ expander, {header: "Id", width: 80, sortable: true, dataIndex: 'id2', id:'Id'}, {header: "Nature", width: 140, sortable: true, dataIndex: 'nature'}, {header: "Useful", width: 140, sortable: true, dataIndex: 'useful'} ]); var mygrid = new Ext.grid.GridPanel({ store: mystore, cm: cm, width: 400, height: 300, plugins: expander, title: 'Expander Rows', renderTo: document.body }); function store_reload(){ mystore.reload() }
-
1 Jul 2008 7:14 AM #17
How to attach rowExpander listener to gridpanel row?
How to attach rowExpander listener to gridpanel row?
Can you (or someone) show me an example of how to attach this? I'm trying:
What I want to happen is to have the doubleclick call the rowExpander's toggleRow method. So far nothing I've tried seems to work. Thanks for any help.Code:// ... listeners : { 'rowdblclick': rowExpander.toggleRow, 'mouseover':chooseActions } ... //Last edited by mystix; 1 Jul 2008 at 7:50 AM. Reason: post code in [code][/code] tags
言い出しっ屁
-
2 Jul 2008 5:11 AM #18
Never mind
Never mind
Turns out I found the solution. I post it here for others who may have this problem.
listeners : {
'rowdblclick': function() { rowExpander.toggleRow(gridSelectionModel.grid.view.getRow(gridSelectionModel.last) )
},
'mouseover':chooseActions
}
... where gridSelectionModel is an Ext.grid.RowSelectionModel.
I really couldn't find anything about this in the docs. The "last" property isn't even mentioned in the properties (actually, there are no properties listed). Maybe my poor searching, but I had to analyze the objects and their properties to even come up with this solution.
Call me crazy, but I think the RowSelectionModel should have a method that returns the row or row index.言い出しっ屁
-
14 Jul 2008 11:46 PM #19
New option added
New option added
This post has helped me a lot, so I coming back to give my contribution.
Added:
- Loading class
- store parameter
- render event
So now this rowExpander can load and apply another store into the tpl.
I have added to this rowExpander the possibility to pass a Data Store to it. The store will be loaded with the value for the id of the row record as param and the result will be applied to the tpl set. After all it will fire the render event passing this.store and record at the end.
RowExpander:
An use example where MemberDS = Ext.data.Store(...):PHP Code:Ext.grid.RowExpander = function(config){
Ext.apply(this, config);
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 = {};
this.addEvents({
beforeexpand : true,
expand: true,
beforecollapse: true,
collapse: true,
render: 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, 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 store is defined it will load up passing id:record.id (grid store)
// in params, use the tpl defined to apply response record (rec)
// and fire the render event with won store and record
if(this.remoteDataMethod){
this.tpl = new Ext.Template("<div id='remData" + rowIndex + "' class='rem-data-expand'><\div>");
}else if(this.store && this.tpl && this.lazyRender){
if(body.innerHTML == '' || !this.enableCaching){
body.innerHTML = Ext.UpdateManager.defaults.indicatorText;
this.store.on('load', function(s,rec){
body.innerHTML = '';
Ext.each(rec,function(e){
body.innerHTML += this.getBodyContent(e, rowIndex);
},this);
this.fireEvent('render', this, record, body, rowIndex, s, rec);
},this,{
scope: this,
single: true
});
this.store.load({params: {id: record.id}});
}
return true;
}
if(this.tpl && this.lazyRender){
body.innerHTML = this.getBodyContent(record, rowIndex);
this.fireEvent('render', this, record, body, 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');
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);
}
}
});
PHP Code:var expander = new Ext.grid.RowExpander({
store: MemberDS,
tpl : new Ext.XTemplate(
'<fieldset><legend>Profile</legend>',
'<tpl if="pic_id">',
'<img id="img_{pic_id}" src="/pics/{pic_id}?'+new Date().getTime()+'" /><br>'
'</tpl>',
'<b>ID:</b> {codea} {codeb}<br>',
'<b>Gender:</b> {gender}<br>',
'<b>DOB:</b> {dob}<br>',
'<b>Category:</b> {category}<br>',
'<b>Comments:</b> {comments}',
'</fieldset>'
)
});
Mandriva Linux in
LAMPE (Linux / Apache / MySQL / PHP / ExtJs)
-
16 Jul 2008 5:35 AM #20
Am I on a correct path?
Am I on a correct path?
I am working an an EditorGridPanel in version 2.1. I searching for clues on how to wrap some Ext components into a RowExpander object.
Am I on the right path? I can see how to use the XTemplate to dump data into a RowExpander, but how would I go about dumping the Ext components (combobox,datefield,etc) for the related parent grid row into the RowExpander?
Any thoughts?
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.


Reply With Quote
