-
7 Aug 2009 3:34 AM #1
ExtendedRowExpander
ExtendedRowExpander
thanks to @bramvano for the idea
thread: http://www.extjs.com/forum/showthrea...472#post369472
usage:PHP Code:package org.yournamehere.client.gui.components;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.core.XTemplate;
import com.extjs.gxt.ui.client.widget.grid.RowExpander;
/**
* A column config and component plugin that adds the ability for each row to be
* expanded, showing custom content that spans all the rows columns.
* with extended control over expanding rows
*
* @author anonym
*/
public class ExtendedRowExpander extends RowExpander {
/**
* Creates a new extended row expander.
*/
public ExtendedRowExpander() {
super();
}
/**
* Creates a new extended row expander with the given template.
*
* @param template the template
*/
public ExtendedRowExpander(XTemplate template) {
super(template);
}
/**
* expand all rows
*
*/
public void expandAllRows() {
for (int rowIndex = 0; rowIndex < grid.getStore().getCount(); rowIndex++) {
this.expandRow(rowIndex);
}
}
/**
* collapse all rows
*
*/
public void collapseAllRows() {
for (int rowIndex = 0; rowIndex < grid.getStore().getCount(); rowIndex++) {
this.collapseRow(rowIndex);
}
}
/**
* toggle all rows
*
* @param expand true to expand, false to collapse rows
*/
public void toggleAllRows(boolean expand) {
if (expand) {
expandAllRows();
} else {
collapseAllRows();
}
}
/**
* expand row
*
* @param rowIndex index of the row
*/
public void expandRow(int rowIndex) {
this.expandRow(getRowAsEl(rowIndex));
}
/**
* collapse row
*
* @param rowIndex index of the row
*/
public void collapseRow(int rowIndex) {
this.collapseRow(getRowAsEl(rowIndex));
}
/**
* toggle row
*
* @param rowIndex index of the row
*/
public void toggleRow(int rowIndex) {
this.toggleRow(getRowAsEl(rowIndex));
}
/**
* toggle row
*
* @param rowIndex index of the row
* @param expand true to expand, false to collapse rows
*/
public void toggleRow(int rowIndex, boolean expand) {
if (expand) {
expandRow(rowIndex);
} else {
collapseRow(rowIndex);
}
}
/**
* get the row as El
*
* @param rowIndex
* @return El row
*/
protected El getRowAsEl(int rowIndex) {
return El.fly(grid.getView().getRow(rowIndex));
}
}
PHP Code:grid.addListener(Events.ViewReady, new Listener<BaseEvent>() {
public void handleEvent(BaseEvent be) {
expander.expandAllRows();
expander.collapseRow(2);
expander.collapseRow(4);
}
});
-
5 Jan 2010 10:36 AM #2
thanks for the idea from siberian - spasibo!
http://www.extjs.com/forum/showthrea...228#post424228
i used the code snippet to adpot a gridcellrenderer to the rowexpander.
problematic points:
- i can not give all parameters to the GridCellRenderer render
- at least a component is needed as returned component from the renderer
so you can use it this way:
1) original usage with templates
2) added usage with gridcellrenderer returning a string:PHP Code:final XTemplate tpl = XTemplate.create("<p><b>Company:</b> {name}</p><br><p><b>Summary:</b> {desc}</p>");
final ExtendedRowExpander expander = new ExtendedRowExpander();
expander.setTemplate(tpl);
3) added usage with gridcellrenderer returning a component:PHP Code:expander.setExpandRenderer(new GridCellRenderer() {
public Object render(ModelData model, String property, ColumnData config, int rowIndex, int colIndex, ListStore store, Grid grid) {
return "<p><b>Company:</b> " + model.get("name") + "</p><br><p><b>Summary:</b>" + model.get("desc") + "</p>";
}
});
herer is the full class - comments are welcome :-)PHP Code:expander.setExpandRenderer(new GridCellRenderer() {
public Object render(ModelData model, String property, ColumnData config, int rowIndex, int colIndex, ListStore store, Grid grid) {
String html = "<p><b>Company:</b> " + model.get("name") + "</p><br><p><b>Summary:</b>" + model.get("desc") + "</p>";
LayoutContainer lc = new LayoutContainer();
lc.setBorders(true);
lc.add(new Button("hallo 1!", new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
Info.display("Button1", "Button 1 clicked!");
}
}));
lc.add(new HtmlContainer(html));
lc.add(new Button("hallo 2!", new SelectionListener<ButtonEvent>() {
@Override
public void componentSelected(ButtonEvent ce) {
Info.display("Button 2", "Button 2 clicked!");
}
}));
return lc;
}
});
PHP Code:package com.mycompany.myapplication.client.gui.components.forum;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.core.XTemplate;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.ComponentHelper;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;
import com.extjs.gxt.ui.client.widget.grid.RowExpander;
import com.google.gwt.user.client.Element;
/**
*
* A column config and component plugin that adds the ability for each row to be
* expanded, showing custom content that spans all the rows columns.
* with extended control over expanding rows
*
* you can add a custom renderer for the expanded part
* thanks to siberian
* http://www.extjs.com/forum/showthread.php?p=424228#post424228
*
* @author anonym
*/
public class ExtendedRowExpander extends RowExpander {
private GridCellRenderer<ModelData> expandRenderer;
java.util.Map<El, Component> layouts = new java.util.HashMap();
/**
* Creates a new extended row expander.
*/
public ExtendedRowExpander() {
super();
}
/**
* Creates a new extended row expander with the given template.
*
* @param template the template
*/
public ExtendedRowExpander(XTemplate template) {
super(template);
}
/**
* expand all rows
*
*/
public void expandAllRows() {
for (int rowIndex = 0; rowIndex < grid.getStore().getCount(); rowIndex++) {
this.expandRow(rowIndex);
}
}
/**
* collapse all rows
*
*/
public void collapseAllRows() {
for (int rowIndex = 0; rowIndex < grid.getStore().getCount(); rowIndex++) {
this.collapseRow(rowIndex);
}
}
/**
* toggle all rows
*
* @param expand true to expand, false to collapse rows
*/
public void toggleAllRows(boolean expand) {
if (expand) {
expandAllRows();
} else {
collapseAllRows();
}
}
/**
* expand row
*
* @param rowIndex index of the row
*/
public void expandRow(int rowIndex) {
this.expandRow(getRowAsEl(rowIndex));
}
/**
* collapse row
*
* @param rowIndex index of the row
*/
public void collapseRow(int rowIndex) {
this.collapseRow(getRowAsEl(rowIndex));
}
/**
* toggle row
*
* @param rowIndex index of the row
*/
public void toggleRow(int rowIndex) {
this.toggleRow(getRowAsEl(rowIndex));
}
/**
* toggle row
*
* @param rowIndex index of the row
* @param expand true to expand, false to collapse rows
*/
public void toggleRow(int rowIndex, boolean expand) {
if (expand) {
expandRow(rowIndex);
} else {
collapseRow(rowIndex);
}
}
/**
* get the row as El
*
* @param rowIndex
* @return El row
*/
protected El getRowAsEl(int rowIndex) {
return El.fly(grid.getView().getRow(rowIndex));
}
/**
* Returns the rowexpanders cell renderer.
*
* @return the renderer
*/
public GridCellRenderer<ModelData> getExpandRenderer() {
return expandRenderer;
}
/**
* Sets the rowexpanders cell renderer (pre-render).
*
* @param expandRenderer the cell renderer
*/
@SuppressWarnings("unchecked")
public void setExpandRenderer(GridCellRenderer expandRenderer) {
this.expandRenderer = expandRenderer;
}
@Override
protected boolean beforeExpand(ModelData model, Element body, El row, int rowIndex) {
if (expandRenderer == null) {
return super.beforeExpand(model, body, row, rowIndex);
} else {
if (fireEvent(Events.BeforeExpand)) {
return makePanel(model, body, row, rowIndex);
}
return false;
}
}
@Override
protected void collapseRow(El row) {
if (fireEvent(Events.BeforeCollapse)) {
row.replaceStyleName("x-grid3-row-expanded", "x-grid3-row-collapsed");
// Detach so we don't bleed memory
if (layouts.get(row) != null) {
ComponentHelper.doDetach(layouts.get(row));
}
layouts.remove(row);
fireEvent(Events.Collapse);
}
}
protected boolean makePanel(ModelData model, Element body, El row, int rowIndex) {
Object detail = expandRenderer.render(model, null, null, rowIndex, 0, ((Grid) grid).getStore(), (Grid) grid);
if (detail instanceof Component) {
layouts.put(row, (Component) detail);
body.setInnerHTML("");
layouts.get(row).render(body);
ComponentHelper.doAttach(layouts.get(row));
} else if (detail != null) {
layouts.put(row, null);
body.setInnerHTML(detail.toString());
} else {
layouts.put(row, null);
body.setInnerHTML("");
}
return true;
}
;
}
This forum needs your help: you got hints from the community and now you have fixed your code? dont just reply with "now its fixed" or "i found the error"! please take the time to post also an detailed answer with the working code.
GreaseMonkey Script for a GXT-only Forum: it hides ExtJs here: New Posts • Search Results • Advanced Search form • Category overview http://www.extjs.com/forum/showthrea...041#post410041
-
12 Jan 2010 2:25 PM #3
a small extension..
a small extension..
I have extended the class, so it is possible to refresh the content of the row without collapsing-extending or refreshing the grid.
Code:/** * refreshes the content of the expander, without closing it * * @param rowIndex */ public void refreshRow(int rowIndex) { El row = getRowAsEl(rowIndex); ModelData model = grid.getStore().getAt(rowIndex); Element body = DomQuery.selectNode("div.x-grid3-row-body", row.dom); body.setInnerHTML(getBodyContent(model, rowIndex)); }
-
14 Jan 2010 9:51 AM #4
thanks for your code :-)
This forum needs your help: you got hints from the community and now you have fixed your code? dont just reply with "now its fixed" or "i found the error"! please take the time to post also an detailed answer with the working code.
GreaseMonkey Script for a GXT-only Forum: it hides ExtJs here: New Posts • Search Results • Advanced Search form • Category overview http://www.extjs.com/forum/showthrea...041#post410041
-
14 Jan 2010 10:30 AM #5
databass requested this:
http://www.extjs.com/forum/showthrea...720#post426720
i do this with my example:I have a multi-column grid, with an additional line for each grid that spans all of the columns.
What I'm trying to do is similar to the RowExpander plugin example in the Grid Plugin example. http://www.extjs.com/examples/explorer.html#gridplugins
But I don't need the interactivity that the plugin has; I just want the second line to span all of the columns and always be visible.
Is there an easy way to set this up?
Otherwise, I could probably modifiy the RowExpanded plugin example. But how could I modifiy this RowExpander plugin to default being Expanded when it's loaded. Right now, it defaults to being UnExpanded.
ForumThread74595FixedLineunder.jpg
you can do this with this codesnippets and the rowexpander:
for the content you can use all variants from the examples in the second posting of this thread ( xTEmplate / returning a String / Returning a widget )PHP Code://... disable the +/-
expander.setRenderer(new GridCellRenderer<ModelData>() {
public String render(ModelData model, String property, ColumnData d, int rowIndex,
int colIndex, ListStore<ModelData> store, Grid<ModelData> grid) {
d.cellAttr = "rowspan='2'";
return "";
}
});
//... create the rowcontent
expander.setExpandRenderer(new GridCellRenderer() {
public Object render(ModelData model, String property, ColumnData config, int rowIndex, int colIndex, ListStore store, Grid grid) {
String html = "<p><b>Company:</b> small line with many text and some other things</p>";
LayoutContainer lc = new LayoutContainer();
lc.setBorders(false);
lc.add(new HtmlContainer(html));
return lc;
}
});
// ... expand all rows
grid.addListener(Events.ViewReady, new Listener<BaseEvent>() {
public void handleEvent(BaseEvent be) {
expander.expandAllRows();
}
});
here is the full example snippet ( extract from the examples explorere examples)
PHP Code:private void createExpander2() {
List<Stock> stocks = TestData.getStocks();
for (Stock s : stocks) {
s.set(
"desc",
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed metus nibh, sodales a, porta at, vulputate eget, dui. Pellentesque ut nisl. Maecenas tortor turpis, interdum non, sodales non, iaculis ac, lacus. Vestibulum auctor, tortor quis iaculis malesuada, libero lectus bibendum purus, sit amet tincidunt quam turpis vel lacus. In pellentesque nisl non sem. Suspendisse nunc sem, pretium eget, cursus a, fringilla vel, urna.<br/><br/>Aliquam commodo ullamcorper erat. Nullam vel justo in neque porttitor laoreet. Aenean lacus dui, consequat eu, adipiscing eget, nonummy non, nisi. Morbi nunc est, dignissim non, ornare sed, luctus eu, massa. Vivamus eget quam. Vivamus tincidunt diam nec urna. Curabitur velit.");
}
List<ColumnConfig> configs = new ArrayList<ColumnConfig>();
final ExtendedRowExpander expander = new ExtendedRowExpander();
expander.setRenderer(new GridCellRenderer<ModelData>() {
public String render(ModelData model, String property, ColumnData d, int rowIndex,
int colIndex, ListStore<ModelData> store, Grid<ModelData> grid) {
d.cellAttr = "rowspan='2'";
return "";
}
});
expander.setExpandRenderer(new GridCellRenderer() {
public Object render(ModelData model, String property, ColumnData config, int rowIndex, int colIndex, ListStore store, Grid grid) {
String html = "<p><b>Company:</b> small line with many text and some other things</p>";
LayoutContainer lc = new LayoutContainer();
lc.setBorders(false);
lc.add(new HtmlContainer(html));
return lc;
}
});
configs.add(expander);
ColumnConfig column = new ColumnConfig();
column.setId("name");
column.setHeader("Company");
column.setWidth(200);
configs.add(column);
column = new ColumnConfig();
column.setId("symbol");
column.setHeader("Symbol");
column.setWidth(100);
configs.add(column);
column = new ColumnConfig();
column.setId("last");
column.setHeader("Last");
column.setAlignment(HorizontalAlignment.RIGHT);
column.setWidth(75);
column.setRenderer(gridNumber);
configs.add(column);
column = new ColumnConfig("change", "Change", 100);
column.setAlignment(HorizontalAlignment.RIGHT);
column.setRenderer(change);
configs.add(column);
column = new ColumnConfig("date", "Last Updated", 100);
column.setAlignment(HorizontalAlignment.RIGHT);
column.setDateTimeFormat(DateTimeFormat.getShortDateFormat());
configs.add(column);
ListStore<Stock> store = new ListStore<Stock>();
store.add(stocks);
ColumnModel cm = new ColumnModel(configs);
ContentPanel cp = new ContentPanel();
cp.setHeading("Expander Rows, Collapse and Auto Fill");
// cp.setIcon(Examples.ICONS.table());
cp.setAnimCollapse(false);
cp.setCollapsible(true);
cp.setLayout(new FitLayout());
cp.setSize(600, 300);
final Grid<Stock> grid = new Grid<Stock>(store, cm);
grid.addPlugin(expander);
grid.setStripeRows(true);
grid.getView().setAutoFill(true);
cp.add(grid);
grid.addListener(Events.ViewReady, new Listener<BaseEvent>() {
public void handleEvent(BaseEvent be) {
expander.expandAllRows();
}
});
grid.getStore().remove(grid.getSelectionModel().getSelectedItem());
panel.add(cp);
}
PS:
maybe as feature of ExtendedRowExpander it can be added to the class :-) something like this: setExpandControlsVisible(boolean visible)This forum needs your help: you got hints from the community and now you have fixed your code? dont just reply with "now its fixed" or "i found the error"! please take the time to post also an detailed answer with the working code.
GreaseMonkey Script for a GXT-only Forum: it hides ExtJs here: New Posts • Search Results • Advanced Search form • Category overview http://www.extjs.com/forum/showthrea...041#post410041
-
14 Jan 2010 12:45 PM #6
Thank you so much. This is exactly what I need. I've added a link to this thread in my original post in the premium forum.
-
20 Jan 2010 9:49 PM #7
Awesome! Thanks for taking it one step further, its much more useful now.
I've replaced my version with yours and its working great.
I still have this problem that when I have a form element with 'setName(..)' invoked on it and I click on that element the row expander collapses. If setName(..) is not called(and thus the form is not bound) it doesn't collapse the row.
Working on a test case, I will post it here when I get it together.
-
28 Feb 2010 1:02 AM #8
Finally have a test case!
Finally have a test case!
If you bind an instance of ModelData to a Form within the ExtendedRowExpander selecting any elements that have a setName that autobinds to an element in the instance of ModelData will force the row to close.
When the row closes it fires no events, it just closes.
Source the shows the problem attached. Press the LoadXML button, expand a row and you'll see some checkboxes.
Checking a box that has no name set works fine.
Checking the box WITH a name set closes the row. Note that the element state is kept, the row is just closed.
If you comment out line 65 ( binding.bind(model); ) you can see that this is the problem.
I can't get deep enough to understand what is happening here. Feels like a CSS class change or something of this nature.
Arno, help!
John-
My row expander widget code also pasted for readability below:
Code:package com.mycompany.project.client; import com.extjs.gxt.ui.client.widget.Composite; import com.extjs.gxt.ui.client.widget.form.CheckBox; import com.extjs.gxt.ui.client.widget.form.FormPanel; import com.extjs.gxt.ui.client.widget.grid.Grid; import com.extjs.gxt.ui.client.widget.LayoutContainer; import com.extjs.gxt.ui.client.widget.layout.AbsoluteData; import com.extjs.gxt.ui.client.widget.layout.RowLayout; import com.extjs.gxt.ui.client.Style.Orientation; import com.extjs.gxt.ui.client.Style.Scroll; import com.extjs.gxt.ui.client.binding.FormBinding; import com.extjs.gxt.ui.client.data.BeanModel; import com.extjs.gxt.ui.client.data.ModelData; import com.google.gwt.user.client.ui.Label; import com.extjs.gxt.ui.client.widget.layout.AbsoluteLayout; import com.extjs.gxt.ui.client.Style; public class DetailPanel extends Composite { public DetailPanel(ModelData model,final Grid grid) { FormPanel layoutContainer = new FormPanel(); FormBinding binding = new FormBinding(layoutContainer); binding.setStore(grid.getStore()); layoutContainer.setLayout(new AbsoluteLayout()); layoutContainer.setHeaderVisible(false); CheckBox chckbxIHaveA = new CheckBox(); chckbxIHaveA.setName("name1"); layoutContainer.add(chckbxIHaveA, new AbsoluteData(12, 48)); chckbxIHaveA.setSize("426px", "22px"); chckbxIHaveA.setBoxLabel("I have a name"); chckbxIHaveA.setHideLabel(true); CheckBox chckbxNoNameHere = new CheckBox(); layoutContainer.add(chckbxNoNameHere, new AbsoluteData(139, 31)); chckbxNoNameHere.setSize("426px", "22px"); chckbxNoNameHere.setBoxLabel("No name here"); chckbxNoNameHere.setHideLabel(true); CheckBox chckbxMyNameIs = new CheckBox(); chckbxMyNameIs.setName("Name"); layoutContainer.add(chckbxMyNameIs, new AbsoluteData(116, 186)); chckbxMyNameIs.setSize("426px", "22px"); //layoutContainer.add(chckbxMyNameIs); chckbxMyNameIs.setBoxLabel("This model name is (random label) "+model.get("Email")); chckbxMyNameIs.setHideLabel(true); CheckBox chckbxIAmAnonymous = new CheckBox(); layoutContainer.add(chckbxIAmAnonymous, new AbsoluteData(140, 142)); chckbxIAmAnonymous.setSize("426px", "22px"); chckbxIAmAnonymous.setBoxLabel("I am anonymous, no name."); chckbxIAmAnonymous.setHideLabel(true); Label label = new Label("My Row Email IS "+model.get("Email")); layoutContainer.add(label, new AbsoluteData(13, 226)); label.setSize("426px", "15px"); layoutContainer.setSize("800px", "178px"); binding.autoBind(); binding.bind(model); initComponent(layoutContainer); layoutContainer.setBorders(true); } }
-
28 Feb 2010 8:05 PM #9
-
19 Mar 2010 10:33 AM #10
Full Eclipse test case + video [Cross post]
Full Eclipse test case + video [Cross post]
Expanded Test case + a video!
Here are links to two items:
1) A full eclipse project that shows the problem
http://snappydog.com/rowexpander/RowExpanderDemo.zip
2) A flash movie demo of the problem in action.
http://snappydog.com/rowexpander/RowExpanderDemo.swf
Basic issue: BeforeCollapse is not fired if the extended rowexpander has widgets in it that are bound to a form. Unbound widgets and anonymous widgets do not have this problem, only bound widgets (via setName("xx")).
This seems like it is a base class issue since the event is never fired from the grid but I am a bit out of my depth here.
Desperate
John-
------------


Reply With Quote