Hybrid View
-
17 Dec 2007 4:10 AM #1
Extending the RowExpander Plugin
Extending the RowExpander Plugin
I've just put up a post on my blog about Extending the RowExpander Plugin, complete with the source and a link to the example page. Basically, I wanted the ability to pass a new argument into the rowexpander, a function reference to be called on expansion. I wanted the ability to populate the expanded area, at the time of expansion, with an Ajax call. Afterwards I showed it to Rey [Bango], who said "get an example up and get it on the forums." So here I am.
You can get the full source of the example from the post, but here's the plugin itself:
After that all you need is a function, and the config to point to it: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); } } });
Code:// FUNCTION: getMyStuff // @param record : actual record in grid row // @param index : row index calling the function function getMyStuff(record,index){ // Using JQuery to 'load' the expanded row with content pulled remotely $('#remData'+index).load('tester.html'); }; var expander = new xg.RowExpander({ remoteDataMethod : getMyStuff });--
Steve "Cutter" Blades
Adobe Community Professional - ColdFusion
Adobe Certified Professional - Advanced Macromedia ColdFusion MX 7 Developer
_____________________________
Blog: Cutter's Crossing
Co-Author "Learning Ext JS 3.2"
-
17 Dec 2007 6:52 AM #2
I have to test this out... but wow... This is very similar to what I had in mind. I may still want to have a container (so that I can load what ever I want there, like say a remote component or another grid etc..) in the expanded section but this is the right direct for it.
Ramki
-
17 Dec 2007 7:36 AM #3
It's in there
It's in there
Thanks Ramki. Actually the call to the remote method will automatically create a container object in the expanded area. There's more info in the blog posting.
--
Steve "Cutter" Blades
Adobe Community Professional - ColdFusion
Adobe Certified Professional - Advanced Macromedia ColdFusion MX 7 Developer
_____________________________
Blog: Cutter's Crossing
Co-Author "Learning Ext JS 3.2"
-
17 Dec 2007 9:08 AM #4
-
21 Dec 2007 4:47 AM #5
I'm trying to use the row expander on my code but its not working..
Edit: Nevermind, solved the problem and its working now..
http://www.ufu.br/ramais/
I'm getting data remotely from a database (ramais.php), so now i need to find out how to get this data remotely and show it on the grid (ramais.js).
-
21 Dec 2007 11:33 AM #6
Thanks
Thanks
Thank you very much Cutter for this plugin,
but I am in need of some more functionality and right now I don't know how to do this. (Never coded a plugin yet, but the rowExpander is that nice I really want to have it)
Two things are missing:
1) I attached a 'celldblclick' event to the grid, thought when the row gets expanded, the visible expanded area doesn't have this event, how can I also attach the celldblclick event to the rowExpander's area for that row?
2) When I have a row expanded and showing the rowExpander, meanwhile updating the grid's datastore (though refreshing the grid), it will show all rows collapsed, even if some of them before the update expanded but the ICON's doesn't get changed. I tried adding an event to the datastore, which then will check all rowExpander.state for that row and replaceClass the Icon but the problem is state only stores the id of the row not the rowIndex itself.
Code:ds.reload( // reload the datastore { callback : function(r, options, success) { if(success) { var expander = XXX.getExpander(); // find all collapsed RowExpander because they won't reset them theirself when the Grid/Store get's updated if(expander.state) { for(row in expander.state) { if(expander.state[row]) // when it was collapsed while updating, it will still show the wrong icon, fix this { expander.state[row] = false; // NEED ROWINDEX HERE NOT ROW! Ext.fly(row).replaceClass('x-grid3-row-expanded', 'x-grid3-row-collapsed'); } } } }
Please someone help me!
Regards,
Iveco
-
25 Mar 2008 8:31 PM #7
Thoughts
Thoughts
Hi CutterBl, I was wonder if you could give me a hand on a dilemma I'm having using RowExpander. I want to render components that I've executed multiple times. I know you can't render a component multiple times, but it seems like a waste to rebuild each time someone clicks the expander on my grid. Here's my forum post; http://extjs.com/forum/showthread.ph...ander+multiple
Based on your post, I'm thought you'd know the answer. BTW I'm a CF dev guy myself.
NNo longer a Newbie
-
1 May 2008 12:22 PM #8
Thanks for the great work
Thanks for the great work
Hi CutterBl
Thanks for the great plugin ... works like a charm ... saved me hours of work.
-
2 May 2008 5:51 AM #9
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 #10
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


Reply With Quote
