firefoxgwtcheckboxcelltablegwt-celltable

GWT Celtable: two clicks needed to change checkbox state in FireFox


In my project i have CellTable with CheckBoxCell column. This is regular column to represent (change) values and doesn't use for row selection (for selection i use SingleSelectionModel). In Chrome everything works fine, on first click I get checkbox state changed and row selected. In FireFox when I try to click on check box in CheckBoxCell column GWT selects row and after second click on checkbox it change checkbox state. But I need the same behavior as in Chrome (change checkbox state on first click).

Here is how i create column:

private <C> Column<T, C> addColumn(CellTable<T> itemListTable, Cell<C> cell, String headerText, int columnWidthPct, final IValueGetter<C, T> getter, @Nullable FieldUpdater<T, C> fieldUpdater) {
    Column<T, C> column = new Column<T, C>(cell) {
        @Override
        public C getValue(T object) {
            return getter.getValue(object);
        }
    };
    column.setFieldUpdater(fieldUpdater);
    column.setSortable(false);
    itemListTable.addColumn(column, headerText);
    itemListTable.setColumnWidth(column, columnWidthPct, PCT);
    return column;
}

private void generateExistingSettingsTable() {
    addColumn(existingSettingsTable, new ParameterizedCheckboxCell<T>(), IS_PUBLIC_HEADER, 10, new IValueGetter<Boolean, T>() {
                @Override
                public Boolean getValue(T setting) {
                    return setting.isPublic();
                }
            },
            new FieldUpdater<T, Boolean>() {
                @Override
                public void update(int index, T object, Boolean value) {
                    object.setPublic(value);
                    updatePublicState(object);
                }
            }
    );
}

My ParameterizedCheckboxCell extends CheckboxCell and overrides only render method (to enable\disable checkbox input).

I already tried everything suggested here here:


Solution

  • As i found out today, the same thing happen with Chrome (version 45.0.2454.101). I investigate this more and find out the following. GWT CheckboxCell by default consume only two browser events: keydown and change. In old Chrome version when you clicked on checkbox change event fired and everything works fine. In FireFox and in the new Chrome version there is no change event after click (i cannot figure out why, explanations are welcome), so i decide to create my own checkbox class that extends AbstractEditableCell<Boolean, Boolean> and replace consumed change to click event. Here is what i got:

    import java.util.Objects;
    
    import com.google.gwt.cell.client.AbstractEditableCell;
    import com.google.gwt.cell.client.ValueUpdater;
    import com.google.gwt.dom.client.Element;
    import com.google.gwt.dom.client.InputElement;
    import com.google.gwt.dom.client.NativeEvent;
    import com.google.gwt.event.dom.client.KeyCodes;
    import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
    
    import static com.google.gwt.dom.client.BrowserEvents.CLICK;
    import static com.google.gwt.dom.client.BrowserEvents.KEYDOWN;
    
    public class ParameterizedCheckboxCell extends AbstractEditableCell<Boolean, Boolean> {
    
        public ParameterizedCheckboxCell() {
            super(KEYDOWN, CLICK);
        }
    
        @Override
        public void render(Context context, Boolean value, SafeHtmlBuilder sb) {
            // Here i have some specific logic so i skip this part
            // You can just copy/paste body of this method from original CheckboxCell
        }
    
        @Override
        public void onBrowserEvent(Context context, Element parent, Boolean value, NativeEvent event, ValueUpdater<Boolean> valueUpdater) {
            final String type = event.getType();
            final boolean enterPressed = KEYDOWN.equals(type) && event.getKeyCode() == KeyCodes.KEY_ENTER;
            if (CLICK.equals(type) || enterPressed) {
                InputElement input = parent.getFirstChild().cast();
                Boolean isChecked = input.isChecked();
    
                if (enterPressed) {
                    isChecked = !isChecked;
                    input.setChecked(isChecked);
                }
    
                if (Objects.equals(value, isChecked)) {
                    clearViewData(context.getKey());
                } else {
                    setViewData(context.getKey(), isChecked);
                }
                valueUpdater.update(isChecked);
            }
        }
    
        @Override
        public boolean isEditing(Context context, Element parent, Boolean value) {
            return false;
        }
    
    }
    

    I skipped dependsOnSelection and handlesSelection because i dont use this for selection column.