Thank you for reporting this bug. We will make it our priority to review this report.
-
Sencha User
[GXT 2.3.1a] In RowEditor#stopEditing ComboBoxes are invalid
After migrating from GXT 2.2.5 to 2.3.1a I've got a problem with RowEditors and ComboBoxes.
When I'm using a ComboBox that doesn't allow empty values and I'm clicking 'Save' in the RowEditor the results will not be saved. After debugging I noticed in the RowEditor#stopEditing method, that ComboBoxes will be cleared (line 503) and I think because of this, the following isValid-check for the RowEditor returns false (ComboBox is empty -> not allowed) and editing is canceled.
Is there a special reason why the ComboBoxes will be cleared? In 2.2.5 I can't find this and everything there is working great. 
Thanks for your help!
EDIT:
In release notes for 2.3.1 I found this bug-fix. I think I could be related to this problem:
- [EXTGWT-3233] - RowEditor Grid - Blank combo value after first edit
EDIT2:
Here is an example with EntryPoint. Compile and open it, than change a row and click save - nothing will be saved.
If you replace the RowEditor with the FixedRowEditor everything works fine. The FixedRowEditor uses the same stopEditing-method than the RowEditor - except the ComboBox#clear() call. So this call should be the problem.
Code:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
import com.extjs.gxt.ui.client.core.FastMap;
import com.extjs.gxt.ui.client.data.BaseModel;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.RowEditorEvent;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.store.Record;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.Viewport;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
import com.extjs.gxt.ui.client.widget.form.Field;
import com.extjs.gxt.ui.client.widget.form.LabelField;
import com.extjs.gxt.ui.client.widget.form.SimpleComboBox;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.grid.CellEditor;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.RowEditor;
public class RowEditorBug implements EntryPoint {
@Override
public void onModuleLoad() {
List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
final SimpleComboBox<String> combo = new SimpleComboBox<String>();
combo.setForceSelection(true);
combo.setTriggerAction(TriggerAction.ALL);
combo.setAllowBlank(false);
combo.add("Yes");
combo.add("No");
CellEditor editor = new CellEditor(combo) {
@Override
public Object preProcessValue(Object value) {
if (value == null) {
return value;
}
return combo.findModel(value.toString());
}
@Override
public Object postProcessValue(Object value) {
if (value == null) {
return value;
}
return ((ModelData) value).get("value");
}
};
ColumnConfig column = new ColumnConfig();
column.setId("yesno");
column.setHeaderHtml("Yes/No");
column.setWidth(130);
column.setEditor(editor);
columns.add(column);
TextField<String> text = new TextField<String>();
text.setAllowBlank(false);
column = new ColumnConfig();
column.setId("name");
column.setHeaderHtml("Name");
column.setWidth(200);
column.setEditor(new CellEditor(text));
columns.add(column);
ColumnModel cm = new ColumnModel(columns);
ListStore<BaseModel> store = new ListStore<BaseModel>();
store.add(createModelData("Yes", "Adam"));
store.add(createModelData("No", "Sam"));
store.add(createModelData("No", "Victoria"));
Grid<BaseModel> grid = new Grid<BaseModel>(store, cm);
grid.setHeight(200);
grid.addPlugin(new RowEditor<BaseModel>());
Viewport vp = new Viewport();
vp.add(grid);
RootPanel.get().add(vp);
}
private BaseModel createModelData(String yesno, String name) {
BaseModel md = new BaseModel();
md.set("yesno", yesno);
md.set("name", name);
return md;
}
private class FixedRowEditor<M extends ModelData> extends RowEditor<M> {
public native void setEditing(boolean editing) /*-{
this.@com.extjs.gxt.ui.client.widget.grid.RowEditor::editing = editing;
}-*/;
public native Record getRecord() /*-{
return this.@com.extjs.gxt.ui.client.widget.grid.RowEditor::record;
}-*/;
public void stopEditing(boolean saveChanges) {
if (disabled || !isEditing()) {
return;
}
setEditing(false);// editing = false;
Map<String, Object> data = new FastMap<Object>();
boolean hasChange = false;
ColumnModel cm = grid.getColumnModel();
for (int i = 0, len = cm.getColumnCount(); i < len; i++) {
if (!cm.isHidden(i)) {
Component c = getItem(i);
if (c instanceof LabelField) {
continue;
} else if (c instanceof Field<?>) {
Field<?> f = (Field<?>) c;
// store may be filtered from previous edit
if (f instanceof ComboBox<?>) {
((ComboBox<?>) f).getStore().clearFilters();
}
String dindex = cm.getDataIndex(i);
Object oldValue = getRecord().get(dindex);
CellEditor ed = cm.getEditor(i);
Object value = ed != null ? ed.postProcessValue(f.getValue()) : f.getValue();
if ((oldValue == null && value != null) || (oldValue != null && !oldValue.equals(value))) {
data.put(dindex, value);
hasChange = true;
}
}
// In original RowEditor the ComboBox will be cleared here
// Don't know why.. it's causing troubles -> removed
}
}
RowEditorEvent ree = new RowEditorEvent(this, rowIndex);
ree.setRecord(getRecord());
ree.setChanges(data);
if (!saveChanges || !isValid()) {
fireEvent(Events.CancelEdit, ree);
} else if (hasChange && fireEvent(Events.ValidateEdit, ree)) {
getRecord().beginEdit();
for (String k : data.keySet()) {
getRecord().set(k, data.get(k));
}
getRecord().endEdit();
fireEvent(Events.AfterEdit, ree);
}
hide();
}
}
}
-
Sencha User
I have exactly the same problem. I did the same workaround as creakie, but I'd like a proper solution.