GWT CellTable: How to Update A TextBox Dynamically - gwt

I have the following CellTable
When the user clicks the Pay Min. CheckBox, it should copy the value from the Due Now column over to the Pay Today text field AND recalculate the total for the Pay Today column.
Here is the code for the CheckboxCell (Pay Min.) and the TextInputCell (Pay Today) columns:
private Column<AccountInvoice, Boolean> buildPayMin() {
columnPayMin = new Column<AccountInvoice, Boolean>(new CheckboxCell(true, false)) {
#Override
public Boolean getValue(AccountInvoice object) {
return object.isPayMinimum();
}
#Override
public void onBrowserEvent(Context context, Element elem, AccountInvoice object, NativeEvent event){
// Get event type
int eventType = Event.as(event).getTypeInt();
// See if this is a 'change' event
if (eventType == Event.ONCHANGE) {
String value = columnMinDue.getValue(object);
// Get the cell to copy the value from
TextInputCell cell = (TextInputCell) columnPayToday.getCell();
// Re-create the view data for the cell
TextInputCell.ViewData viewData = new TextInputCell.ViewData(value);
cell.setViewData(object, viewData);
// Refresh
cellTable.redraw();
event.preventDefault();
event.stopPropagation();
}
}
};
columnPayMin.setDataStoreName(columnPayMinHeader);
columnPayMin.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
columnPayMin.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
return columnPayMin;
}
// -----------------------------------------------------------
private Column<AccountInvoice, String> buildPayToday() {
columnPayToday = new Column<AccountInvoice, String>(new TextInputCell()) {
#Override
public String getValue(AccountInvoice object) {
return object.getPaymentAmount();
}
};
columnPayToday.setDataStoreName(columnPayTodayHeader);
columnPayToday.setFieldUpdater(new FieldUpdater<AccountInvoice, String>() {
#Override
public void update(int index, AccountInvoice object, String value) {
object.setPaymentAmount(value);
cellTable.redraw();
}
});
return columnPayToday;
}
I can get the value to copy over, but the total for the Pay Today column doesn't refresh. It seems to refresh only when a value is manually entered into the Pay Today text field. I even tried doing:
columnPayToday.getFieldUpdater().update(context.getIndex(), object, value);
which didn't help either.
Thanks for any help you might provide.

ViewData represents a temporary value in your TextInputCell. When you call cellTable.redraw(), the TextInputCell reverts to the original value (the one from getValue() method for that column).
Do not redraw the table if you want to modify only the "view" state of TextInputCell, or call accountInvoice.setPayToday# (or whatever method is there) to update the object and then call refresh() on your ListDataProvider (which is a more efficient way to update a table compared to redraw).

Related

In GWT CellTable, how can I make a cell consume a click event so it wont reach the row?

I have a CellTable with a few rows for which I use MultiSelectionModel. The first column is a column of checkbox cells.
When the user checks one of the checkboxes the row becomes selected (as per the example in the site) and when the user clicks a row a function "doActionOnRow()" is called.
My problem is that when the user checks a checkbox the "doActionOnRow()" is also called. How can I make the CheckboxCell consume the click event so it wont be triggered on the celltable as well ?
EDIT:
This is my code:
table.addCellPreviewHandler(new Handler<Patient>() {
#Override
public void onCellPreview(CellPreviewEvent<Patient> event) {
boolean isClick = "click".equals(event.getNativeEvent().getType());
if (isClick) {
doSomething();
}
}});
Column<Patient, Boolean> checkColumn = new Column<Patient, Boolean>(new CheckboxCell(true, false)) {
#Override
public Boolean getValue(Patient object) {
// Get the value from the selection model.
return sm.isSelected(object);
}
#Override
public void onBrowserEvent(Context context, Element elem, Patient patient, NativeEvent event) {
if ("click".equals(event.getType()))
event.stopPropagation();
super.onBrowserEvent(context, elem, patient, event);
}
};
table.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>"));
Even when I add event.stopPropagation(); doSomething(); is called when I click the checkbox.
Any idea why ?
You need to check where the event happens first (on the cell or on the row: I forgot that point). then you just call event.stopPropagation()
You can also decide in your column whether you want to do something with the click this way (snippet from my project)
productColumn = new Column<ProductProxy, ProductProxy>(productCoreCell) {
#Override
public ProductProxy getValue(ProductProxy productProxy) {
return productProxy;
}
#Override
public void onBrowserEvent(Context context, Element elem, ProductProxy object, NativeEvent event) {
getProductTableManager().rowSelected(object);
}
};

Create GWT Datagrid with a checkbox column

I have successfully created a datagrid table with two columns. A checkbox col and a string col. When I press a button I want to get the selected strings. Currently when I press the button i get an empty hash set.
Selection Model:
private MultiSelectionModel<String> selectionModel = new MultiSelectionModel<String>(KEY_PROVIDER);
Here is how I create the column
Column<String, Boolean> checkColumn =
new Column<String, Boolean>(new CheckboxCell(true, false)) {
#Override
public Boolean getValue(String object) {
// Get the value from the selection model.
return selectionModel.isSelected(object);
}
};
Here is the method that is called from the button
public Set<String> getSelectedItems(){
Set<String> s = selectionModel.getSelectedSet();
return s;
}
Two pieces are missing. You need to add a FieldUpdater to your checkColumn, and you need to link it to a checkbox manager. Replace T with your Object:
checkColumn.setFieldUpdater(new FieldUpdater<T, Boolean>() {
#Override
public void update(int index, T object, Boolean value) {
getSelectionModel().setSelected(object, value);
dataProvider.refresh();
}
});
setSelectionModel(selectionModel, DefaultSelectionEventManager.<T> createCheckboxManager(0));

GWT Header CheckBox requires two clicks to fire setValue, after changing its value programatically

I have a GWT DataGrid, and a CheckBox in the Header to select/deselect all rows in the grid.
The code for the CheckBox Header is as follows:
private class CheckboxHeader extends Header<Boolean> implements HasValue<Boolean> {
private boolean checked;
private HandlerManager handlerManager;
/**
* An html string representation of a checked input box.
*/
private final SafeHtml INPUT_CHECKED = SafeHtmlUtils.fromSafeConstant("<input type=\"checkbox\" tabindex=\"-1\" checked/>");
/**
* An html string representation of an unchecked input box.
*/
private final SafeHtml INPUT_UNCHECKED = SafeHtmlUtils.fromSafeConstant("<input type=\"checkbox\" tabindex=\"-1\"/>");
#Override
public void render(Context context, SafeHtmlBuilder sb) {
if (Boolean.TRUE.equals(this.getValue())) {
sb.append(INPUT_CHECKED);
} else {
sb.append(INPUT_UNCHECKED);
}
};
public CheckboxHeader() {
super(new CheckboxCell(true, false));
checked = true;
}
// This method is invoked to pass the value to the CheckboxCell's render method
#Override
public Boolean getValue() {
return checked;
}
#Override
public void onBrowserEvent(Context context, Element elem, NativeEvent nativeEvent) {
int eventType = Event.as(nativeEvent).getTypeInt();
if (eventType == Event.ONCHANGE) {
nativeEvent.preventDefault();
// use value setter to easily fire change event to handlers
setValue(!checked, true);
}
}
#Override
public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Boolean> handler) {
return ensureHandlerManager().addHandler(ValueChangeEvent.getType(), handler);
}
#Override
public void fireEvent(GwtEvent<?> event) {
ensureHandlerManager().fireEvent(event);
}
#Override
public void setValue(Boolean value) {
setValue(value, true);
}
#Override
public void setValue(Boolean value, boolean fireEvents) {
checked = value;
if (fireEvents) {
ValueChangeEvent.fire(this, value);
}
}
private HandlerManager ensureHandlerManager() {
if (handlerManager == null) {
handlerManager = new HandlerManager(this);
}
return handlerManager;
}
}
So, I add the Header to the grid, and I add a ValueChangeHandler to it to do the actual selecting/deselecting of individual CheckBox cells in every row of the grid. This all works.
Every CheckBoxCell has a Field Updater, and on every update it loops through every item in the grid to see if they are all checked, and update the header check box. If at least one is unchecked, the header checkbox will be unchecked. I call setValue() on the header check box, and after that I call redrawHeaders() on the entire grid. This also works.
What doesn't work is - after changing the "state" of the header check box programatically, it takes two clicks for it to fire it's internal setValue again, and therefore trigger my handler. And what's even funnier - the first click does change the state of the check box, but it just doesn't fire the event.
Any help would be appreciated.
How are you constructing the CheckboxCells themselves? I ran into a similar issue with a column of checkboxes "eating" clicks, and the solution was to call CheckboxCell cell = new CheckboxCell(true,true) and then pass that cell into the constructor of the column.

GWT CellTable Cells readOnly/disabled/non-editable

I want to make that some cells of the rows can be non-editable.
by now my solution is when i create the columns, if one is readOnly, y make a TextCell, if not, i go with the default Cell wich can be EditTextCell,DatePickerCell,etc.
The problem with this is that i can't make some rows readOnly and others not. Or they are ALL the fields readOnly or they are not.
How can i do to make this for example
TABLE:
Data1 | Data2 | Data3
--------------------------------------
readOnly | non-readOnly | readOnly
readOnly | readOnly | non-readOnly
when i mean "readOnly" it can be "enabled" or make it a "TextCell"
celda = new TextInputCell();
Column<ObjetoDato, String> columna = new Column<ObjetoDato, String>(celda) {
#Override
public String getValue(ObjetoDato object) {
if(actual.getValorDefault()!=null && object.getValor(actual.getNombreCampo()).isEmpty()){
object.setValor(actual.getNombreCampo(), actual.getValorDefault());
return actual.getValorDefault();
}
return object.getValor(actual.getNombreCampo());
}
};
tabla.agregarColumna(columna, actual.getCaption());
columna.setFieldUpdater(new FieldUpdater<ObjetoDato, String>() {
#Override
public void update(int index, ObjetoDato object, String value) {
object.setValor(actual.getNombreCampo(), value);
new Scripter(object,actual.getComportamiento(),true);
tabla.actualizar();
Sistema.get().getIG().actualizarTotales();
}
});
I tried creating my cutom cell already and replacing the TextImputCell, but the methods never trigger
celda = new FabriCel();
and
public class FabriCel extends TextInputCell {
private String campo;
public FabriCel(String campo){
this.campo=campo;
}
#Override
public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event, ValueUpdater<String> valueUpdater){
Boolean editable = false;///get it from your model
if(editable != null && !editable){
event.preventDefault();
}else{
super.onBrowserEvent(context, parent, value, event, valueUpdater);
}
}
Also this
#Override
public void render(com.google.gwt.cell.client.Cell.Context context, String value, SafeHtmlBuilder sb) {
Boolean editable = false;///get it from your model
if(editable){
Log.log();
sb.appendHtmlConstant("<div contentEditable='false'>" +value+"</div>");
}else{
Log.log("No entra");
super.render(context, value, sb);
}
}
Thanks!
You have to create one custom cell. In that, you have tell runtime like it should be readonly or no-readonly. just example.
private class CustomCell extends EditTextCell {
public void render(com.google.gwt.cell.client.Cell.Context context,
String value, SafeHtmlBuilder sb) {
Data data=context.getKey();
if(data.isReadOnly()){
sb.appendHtmlConstant("<div contentEditable='false'
unselectable='false' >" +value+"</div>");
}else{
super.render(context, value, sb);
}
}
}
In given bean, there is some condition which says readonly or no-readonly.
And create column like
Column<Data, String> nameColumn = new Column<Data, String>(new CustomCell()) {
#Override
public String getValue(Data object) {
return object.getName();
}
};
A way to do this is to override the onBrowserEvent event of your Editable Cells and consume the event if the cell is not editable.
final EditTextCell cell = new EditTextCell(renderer)
{
#Override
public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event, ValueUpdater<String> valueUpdater)
{
Boolean editable = false;///get it from your model
if(editable != null && !editable)
{
event.preventDefault();
}
else
{
super.onBrowserEvent(context, parent, value, event, valueUpdater);
}
}
}
I had the same need; and tested out various combinations of overriding render, isEditing, resetFocus, and edit on EditTextCell (I didn't try the onBrowserEvent solution).
When I only overrode render (to show an HTML value if non-editable); I got errors resetting focus (as discussed here). This continued even if I overrode resetFocus. When I only override isEditing, the cell would flash to editing when clicked, and then flash back. What worked perfectly was overriding edit. I triggered based on adding a tag to the value passed in by Column.getValue, you can trigger however you like, but it turned out to be as simple as:
private static class LockableEditTextCell extends EditTextCell {
#Override
protected void edit(Context context, Element parent, java.lang.String value) {
if (!value.startsWith(LOCKED_CELL_VALUE)) {
super.edit(context, parent, value);
}
}
}

How to add a Clickhandler to a cellTable cell (or row )

I would like to have a handler on a column of my cellTable.The column is an ImageResourceCell and I would that when I click on it, it delete the row
Here is my code
Column<MyObject, ImageResource> imageColumn =
new Column<MyObject, ImageResource>(newImageResourceCell()) {
#Override
public ImageResource getValue(MyObject object) {
return Bundle.Util.getInstance().deleteRegexButton();
}
};
cellTable.addColumn(imageColumn,SafeHtmlUtils.fromSafeConstant("<br/>");
But I didn't know how to insert a handler as described
Is it possible ??
any suggestions are welcome
Thanks.
Cells have to declare the events they handle, then the browser event can be passed to the cell.
ImageResourceCell myImgCell = new ImageResourceCell() {
public Set<String> getConsumedEvents() {
HashSet<String> events = new HashSet<String>();
events.add("click");
return events;
}
};
Column<MyObject, ImageResource> imageColumn = new Column<MyObject, ImageResource>(myImgCell) {
#Override
public ImageResource getValue(MyObject dataObj) {
return Bundle.Util.getInstance().deleteRegexButton();
}
#Override
public void onBrowserEvent(Context context, Element elem,
MyObject object, NativeEvent event) {
super.onBrowserEvent(context, elem, object, event);
if ("click".equals(event.getType())) {
//call your click event handler here
}
}
};
More info here: http://code.google.com/webtoolkit/doc/latest/DevGuideUiCustomCells.html
Note: this works with GWT 2.4, did not try with GWT 2.2.
Have you seen Adding clickHandler to row in CellTable in GWT??
A CellTable has built in support for handling click events. You can add a CellPreviewHandler that will be called among others when a row is clicked. It will receive a number of items in the event like the native event, cell, and data row value. Because it fires not only for click events you need to check if the click event was fired. Simply test the event passed:
boolean isClick = "click".equals(event.getNativeEvent().getType())