I'm trying to pull out the required code from Custom DataGrid Example
to achieve expandable rows as shown in said example (click on "show friends" cell) but the provided source is so bloated that it's not as easy as it seems.
Does anyone have more straightforward example how to achieve expandable rows on DataGrid?
I had the same problem like you and developed the following solution:
POJO which contains all necessary information about a row, also it contains the children rows which can be opened:
import java.util.List;
public class MyPojo {
private String value;
private List<MyPojo> children;
public MyPojo(String value, List<MyPojo> children) {
this.value = value;
this.children = children;
}
public String getValue1() {
return value;
}
public List<MyPojo> getChildren() {
return children;
}
}
And now the datagrid
which contains rows which can be opened:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.gwt.cell.client.ClickableTextCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.text.shared.AbstractSafeHtmlRenderer;
import com.google.gwt.text.shared.SafeHtmlRenderer;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.DataGrid;
import com.google.gwt.user.cellview.client.TextColumn;
public class MyGrid extends DataGrid<MyPojo> {
private List<MyPojo> allRows = new ArrayList<>();
private final Set<MyPojo> openedRows = new HashSet<MyPojo>();
public MyGrid() {
TextColumn<MyPojo> column1 = new TextColumn<MyPojo>() {
@Override
public String getValue(MyPojo object) {
return object.getValue1();
}
};
addColumn(column1, "Column1");
SafeHtmlRenderer<String> anchorRenderer = new AbstractSafeHtmlRenderer<String>() {
@Override
public SafeHtml render(final String object) {
if (!object.isEmpty()) {
SafeHtmlBuilder sb = new SafeHtmlBuilder();
sb.appendHtmlConstant("<a href=\"javascript:;\">").appendEscaped(object)
.appendHtmlConstant("</a>");
return sb.toSafeHtml();
}
return null;
}
};
Column<MyPojo, String> openRowColumn = new Column<MyPojo, String>(
new ClickableTextCell(anchorRenderer)) {
public String getValue(final MyPojo object) {
if (object.getChildren() != null && object.getChildren().size() != 0) {
if (openedRows.contains(object)) {
return "Hide";
}
return "Open";
} else {
return null;
}
}
};
addColumn(openRowColumn, "Open Column");
openRowColumn.setFieldUpdater(new FieldUpdater<MyPojo, String>() {
@Override
public void update(final int index, final MyPojo object, final String value) {
handleChild(index, object);
}
});
addContent();
}
private void handleChild(int index, MyPojo object) {
List<MyPojo> children = object.getChildren();
if (children != null && children.size() != 0 && !openedRows.contains(object)) {
allRows.addAll(index + 1, children);
openedRows.add(object);
setRowData(allRows);
} else if (openedRows.contains(object)) {
for (int i = 0; i < children.size(); i++) {
allRows.remove(index + 1);
}
openedRows.remove(object);
setRowData(allRows);
}
}
private void addContent() {
MyPojo child = new MyPojo("Child 1", null);
List<MyPojo> children = new ArrayList<>();
children.add(child);
for (int i = 0; i < 5; i++) {
allRows.add(new MyPojo("c" + i, children));
}
setRowData(allRows);
}
}
The idea is to track the rows which are opened, therefore we use the HashSet openedRows
. If a user clicks on open/close either the children are added below the clicked entry or the the visible children will be removed.
A downside of this approach is that the table can not be sorted, because this will mix up the children and parent entries. I also did not test what happens when rows are deleted/manipulated/inserted.
There may be better or simpler approaches (unknown to me), but this one is relatively straightforward and should work reliable if no modification is needed.