Im using a GWT Cell Table with sorting enabled on the columns. I am also providing an option of filtering the column. This is roughly how the header looks.
----ColumnName (Image) -------
When the user clicks on the image, i start off a filtering process. I achieved this using the Cell Table's addCellPreviewHandler. The issue I am facing is , when the image is clicked , the column sorts itself too. Can anyone tell me how to prevent this from happening ? To be clearer, I want the sort to be called when the user clicks anywhere in the header but the image.
Thanks.
breakDownCellTable.addColumn(indexedColumn, columnHeader);
final int currentColumnIndex = columnIndex;
// Add a ColumnSortEvent.ListHandler to connect sorting to the
// java.util.List.
ListHandler<List<GwtContributorCellData>> columnSortHandler = new ListHandler<List<GwtContributorCellData>>(contributorList);
columnSortHandler.setComparator(indexedColumn, new Comparator<List<CustomClass>>() {
public int compare(List<CustomClass> o1, List<CustomClass> o2) {
if (o1 == o2) {
return 0;
}
// Compare the columns.
if (o1 != null) {
return (o2 != null) ? o1.get(currentColumnIndex).compareTo(o2.get(currentColumnIndex)) : 1;
}
return -1;
}
});
breakDownCellTable.addColumnSortHandler(columnSortHandler);
and in the onBrowserEvent method:
if("click".equals(event.getType())){
EventTarget eventTarget = event.getEventTarget();
if(eventTarget.toString().contains("img") && !eventTarget.toString().contains("<th")){
//event.stopPropagation();
// Window.alert("here");
//breakDownCellTable.fireEvent()
ColumnSortEvent.fire(breakDownCellTable, breakDownCellTable.getColumnSortList());
Your can implement a subclass of the cell you're using and override the onBrowserEvent() method.
This post explains how to find out which DOM element is the exact source of the event.
Once you know that the image has been clicked or not, fire the filtering / sorting event accordingly.
Related
We have a NatTable with no header and I treated the 1st row as a Header,
- Register CELL_PAINTER to change the visualization to look this row similar to header.
Also registered the CustomCommandHandler which implements ILayerCommandHandler to prevent cell/row selection for the 1st row.
selectionLayer.registerCommandHandler(new CustomCommandHandler());
Cell selection is working fine for other cells.
public boolean doCommand(final ILayer layer, final ILayerCommand command)
{
if (command instanceof ViewportSelectRowCommand)
{
return ((ViewportSelectRowCommand) command).getRowPosition() <= 1;
}
else if (command instanceof SelectCellCommand)
{
return ((SelectCellCommand) command).getRowPosition() <= 1
}
return false;
}
Now how can I select the entire column on selecting cells on 1st row. So that it should not affect the cell selection for other row cells.
Clicking any cells on 1st row should select entire column.
Clicking any cells on other rows should select the same cell. (currently this is happening)
Although I am not quite sure what sense it makes to only have a body that is configured in a complicated way to look and behave like it has headers without really having headers (IMHO this does not make any sense), you need to register a custom handler that checks for the column position and transform the SelectCellCommand into a SelectColumnCommand.
this.selectionLayer.registerCommandHandler(new SelectCellCommandHandler(this.selectionLayer) {
#Override
public boolean doCommand(ILayer targetLayer, SelectCellCommand command) {
if (command.convertToTargetLayer(targetLayer)
&& command.getColumnPosition() == 0) {
return targetLayer.doCommand(
new SelectColumnCommand(
targetLayer,
command.getColumnPosition(),
command.getRowPosition(),
command.isShiftMask(),
command.isControlMask()));
}
return super.doCommand(targetLayer, command);
}
});
But I expect there will be more issues on the way as the immitated headers do not behave like real headers also in other scenarios. You could also try to override getRegionLabelsByXY(int, int) but I am not sure if this would work or cause more problems.
Ok, so I have a pretty specific and to me quite complicated issue, as I'm a GWT newbie.
I have a GWT flex table, which I use to dynamically add rows, whose cells contain GWT widgets. The row number changes, but the number of columns in static, always 6. Each row contains a cell with a remove button and five cells each with their own textbox.
What I need to do is somehow code a kind of relationship between the textbox in cell 6 of one row and the textbox in cell 5 in the next row (and vice versa).
To illustrate: when something changes in the textbox at [1,6] the content of textbox at [2,5] needs to be overwritten with the same value. If the textbox at [2,5] changes the textbox at [1,6] needs to change as well. I cannot use a button to commit the changes, it needs to happen via onValueChange or Blur or something similar, which doesn't require the user to perform a specific action.
My problem stems mostly from trying to figure out how to address specific cells in the flex table and their content. For the remove button the solution was easy enough with a click event handler, but for this issue I just can't seem to be able to come up with a solution.
Sadly I also cannot provide any of the code which I have up until now, since it's a business secret. I can only give a broad description of the problem like the one above.
EDIT:
Actually, it's probably more a problem of not having much code in terms of this specific problem.
What I have is a flex table, which has initially only the header row. Upon clicking a button below this table the addNewField() method is called, which just contains the creation, setting of default values and adding of the text fields into a new row.
addNewField() {
int rows = flextable.getRowCount();
Button removeBtn = new Button("x");
removeBtn.getElement().setId(Integer.toString(rows));
//then the button's event handler
TextBox name = new TextBox();
name.setText("something");
flextable.setWidget(rows, 0, "name");
//repeat 4 more times with incrementing columns for the other widgets
}
This way I add entire rows of editable TextBoxes. What I need is a way to influence the values of the 6th column TextBox of a chosen row and the 5th column TextBox of chosen row + 1.
EDIT2: I've tried the dirty option just to see how it would go and somehow the compare inside the if breaks the app. The compiler detects a nullpointerexception and I can't even debug it with breakpoints because it fails to compile and won't start. I can't figure out why though. I threw the code directly into the event for testing purposes, so pardon the ugliness.
TextBox bis = new TextBox();
bis.setText(rows + ":10:00");
subs.setWidget(rows, 5, bis);
bis.addValueChangeHandler(new ValueChangeHandler<String>()
{
#Override
public void onValueChange(ValueChangeEvent<String> event)
{
allRows: for (int i = 0; i < subs.getRowCount(); i++)
{
for (int j = 0; j < subs.getCellCount(i); j++)
{
if ( subs.getWidget(i, j) == bis )
{
TextBox widgetAtColumnSix = ((TextBox) subs.getWidget(i, 5));
String text = widgetAtColumnSix.getText();
TextBox widgetAtColumnFiveRowPlusOne = ((TextBox) subs.getWidget(i + 1, 4));
widgetAtColumnFiveRowPlusOne.setText(text);
break allRows;
}
}
}
}
});
EDIT: Since you edited your question and you dont want to use EventBus you could iterate over your FlexTable and set your TextBox value depending on your current rowIndex and cellIndex... Its not nice but it should work:
public class CellWidget extends Composite {
private TextBox nameBox;
public CellWidget() {
FlowPanel flowPanel = new FlowPanel();
Button deleteButton = new Button("x");
nameBox = new TextBox();
nameBox.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
notifiyTextBox(CellWidget.this, event.getValue());
}
});
flowPanel.add(nameBox);
flowPanel.add(deleteButton);
initWidget(flowPanel);
}
public void setText(String text) {
nameBox.setText(text);
}
}
public void notifiyTextBox(CellWidget source, String string) {
rows: for (int i = 0; i < flextable.getRowCount(); i++) {
columns: for (int j = 0; j < flextable.getCellCount(i); j++) {
if (flextable.getWidget(i, j) == source) {
CellWidget widgetAtColumnSix = ((CellWidget) flextable.getWidget(i, 5));
widgetAtColumnSix.setText(string);
CellWidget widgetAtColumnFiveRowPlusOne = ((CellWidget) flextable.getWidget(i + 1, 4));
widgetAtColumnFiveRowPlusOne.setText(string);
break rows;
}
}
}
}
I still would recommend using an eventbus. To make it even more convenient there is the GWT Event Binder lib, which makes using events a breeze.
So when you change a value in your textbox[2,5] it also fires your CustomEvent. All Widgets, that need to change their textbox value just need to catch...
I created a new tool in ContentTools that adds a static table (I don't want you to edit).
But being a static element doesn't maintain focus and I can not remove it when I click remove button.
I can do so that the table is not editable but can be removed if you click on it?
That's how I created the element:
new ContentEdit.Static('div', {'data-ce-moveable': true}, '<table><thead><tr><th>Foo head</th></tr></thead><tbody><tr><td>Foo body</td></tr></tbody></table>')
Thank you!
Static elements can't be interacted with for the most part (other elements can be dragged around them but that's about it). ContentEdit/Tools does allow you to restrict the some behaviour for elements but not being able to modify the content of a text element isn't one right now (though I think this might be a worthy addition).
However whilst there's no set way to do this at the moment here's an approach you can use that should provide the behaviour you describe (do let me know how you get on):
ContentEdit.Root.get().bind('mount', function(element) {
// We only care about `TableCell` elements
if (element.type() != 'TableCell') {
return;
}
// We only want to make the element read-only if the parent table has
// the `data-read-only` attribute.
var table = element.closest(function(node) {
return node.type() == 'Table';
});
if (table.attr('data-read-only') !== undefined) {
// Disable text editing for the table cell
element.tableCellText()._onKeyDown = function(ev) {
ev.preventDefault();
}
}
// Disable dragging of the table rows
var tableRow = element.closest(function(node) {
return node.type() == 'TableRow';
});
tableRow.can('drag', false);
tableRow.can('drop', false);
});
I have some dependencies hierarchy on my form, so I implemented hierarchy check on server side of the scout. If one field is changed, it triggered check if other need to be changed as well. This is done with export/import form data.
MyFormData input = new MyFormData();
FormDataUtility.exportFormData(this, input);
input = BEANS.get(IMYService.class).validate(input, field);
FormDataUtility.importFormFieldData(this, input, false, null, null);
validate function change all other fields that need to be changed.
My problem is with editing cells in editable tables.
If I change value in cell, and this chain validation is triggered, after importing form data I lose focus in cell. So instead, tab will move me to another cell, tab trigger import and focus in cells are lost. And this is a really bad user experience.
How to fix this?
How to stay in focus (of next cell) after import has been called?
Marko
I am not sure, if this applies for you, but you can try the following:
I assume, that you do your export/validate/import logic in the execCompleteEdit(ITableRow row, IFormField editingField) of your column class. I suggest, that you calculate your next focusable cell by yourself and request its focus after importing the form data.
As an example, you can do this like that:
#Override
protected void execCompleteEdit(ITableRow row, IFormField editingField) {
super.execCompleteEdit(row, editingField);
// create form data object
// export form data
// call service and validate
// import form data
// request focus for next cell
focusNextAvailableCell(this, row);
}
with focusNextAvailableCell(this, row) as following:
private void focusNextAvailableCell(IColumn<?> col, ITableRow row) {
if (col == null || row == null) {
return;
}
IColumn<?> nextColumn = getColumnSet().getColumn(col.getColumnIndex()+1);
ITableRow nextRow = getTable().getRow(row.getRowIndex());
if (nextColumn == null) {
// no next column (last column lost focus)
// check if next row is available
nextRow = getTable().getRow(row.getRowIndex()+1);
// maybe select first cell again?
if (nextRow == null) {
nextColumn = getColumnSet().getColumn(0);
nextRow = getTable().getRow(0);
}
}
if (nextColumn != null && nextRow != null) {
getTable().requestFocusInCell(nextColumn, nextRow);
}
}
You should be aware, that you have to call this after every form data import in your execCompleteEdit method of your column. Also this is triggered not only when switching cells through pressing the tab key, but also when clicking with the mouse button.
Best regards!
GWT's CellBrowser is a great way of presenting dynamic data.
However when the browser contains more rows than some (seemingly) arbitrary maximum, it offers a "Show More" label that the user can click to fetch the unseen rows.
How can I disable this behavior, and force it to always show every row?
There are several ways of getting rid of the "Show More" (which you can combine):
In your TreeViewModel, in your NodeInfo's setDisplay or in the DataProvider your give to the DefaultNodeInfo, in onRangeChange: overwrite the display's visible range to the size of your data.
Extend CellBrowser and override its createPager method to return null. It won't change the list's page size though, but you can set it to some very high value there too.
The below CellBrowser removes the "Show More" text plus loads all available elements without paging.
public class ShowAllElementsCellBrowser extends CellBrowser {
public ShowAllElementsCellBrowser(TreeViewModel viewModel, CellBrowser.Resources resources) {
super(viewModel, null, resources);
}
#Override
protected <C> Widget createPager(HasData<C> display) {
PageSizePager pager = new PageSizePager(Integer.MAX_VALUE);
// removes the text "Show More" during loading
display.setRowCount(0);
// increase the visible range so that no one ever needs to page
display.setVisibleRange(0, Integer.MAX_VALUE);
pager.setDisplay(display);
return pager;
}
}
I found a valid and simple solution in setting page size to the CellBrowser's builder.
Hope this will help.
CellBrowser.Builder<AClass> cellBuilder = new CellBrowser.Builder<AClass>(myModel, null);
cellBuilder.pageSize(Integer.MAX_VALUE);
cellBrowser = cellBuilder.build();
The easiest way to do this is by using the:
cellTree.setDefaultNodeSize(Integer.MAX_VALUE);
method on your Cell Tree. You must do this before you begin expanding the tree.
My workaround is to navigate through elements of treeview dom to get "show more" element with
public static List<Element> findElements(Element element) {
ArrayList<Element> result = new ArrayList<Element>();
findShowMore(result, element); return result; }
private static void findShowMore(ArrayList res, Element element) {
String c;
if (element == null) { return; }
if (element.getInnerText().equals("Show more")) { res.add(element);
}
for (int i = 0; i < DOM.getChildCount(element); i++) { Element
child = DOM.getChild(element, i); findShowMore(res, child); } }
and than use:
if (show) { element.getStyle().clearDisplay(); } else {
element.getStyle().setDisplay(Display.NONE); }