PDA

View Full Version : RE-POST: Bug in SimpleComboBox and FormBinding?



flyinghang
28 Jul 2009, 6:10 PM
Hi all,

Two weeks ago, I posted a thread indicated that the SimpleComboBox maybe work incorrect with a FormBinding. But the post was closed by sven because my test code had quite a little issue. see the original post: http://extjs.com/forum/showthread.php?t=74114

So , I modifed my test code using the new GWT 1.7 and gxt 2.0.1 and I found the problem is still there.

here is the old post with new test code.
---------------------------------

I am using a Grid and a Form with a FormBinding, a combobox , a TextField and a submit button,
when user select a grid row, then combobox and textfield will display the field value of the row, then user can modify the value in combobox(setforceselection = false) or in the TextField, but I found if user press the Test button, value in TextField can send back to grid correctly, but the combobox is not unless user click the TextField(force to blur).

Here is the test code, just select one grid row, and then change the value of combobox, do nothing but just press the Test button. if store.getModifiedRecords = 0, a Info will display.
if the bug won't show, just try again.

GWT version: 1.6
GXT version: 2.0
Hosted Mode
Windows XP




package com.flyinghang.test.client;

import java.util.ArrayList;
import java.util.List;

import com.extjs.gxt.ui.client.Style.SelectionMode;
import com.extjs.gxt.ui.client.binding.FormBinding;
import com.extjs.gxt.ui.client.binding.SimpleComboBoxFieldBinding;
import com.extjs.gxt.ui.client.data.BaseModelData;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedListener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Info;
import com.extjs.gxt.ui.client.widget.Viewport;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.FormPanel;
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.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.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.layout.RowData;
import com.extjs.gxt.ui.client.widget.layout.RowLayout;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;

public class Test implements EntryPoint {

@Override
public void onModuleLoad() {
// TODO Auto-generated method stub

Viewport port = new Viewport();

port.setLayout(new FitLayout());
ContentPanel c = new ContentPanel();
c.setHeight(500);
c.setHeading("Combobox test");

c.setLayout(new RowLayout());

FormPanel p = new FormPanel();
p.setHeaderVisible(false);

c.add(p);

SimpleComboBox<String> cb = new SimpleComboBox<String>();
cb.setForceSelection(false);

cb.add("a");
cb.add("b");
cb.add("c");

cb.setName("value");
cb.setFieldLabel("Test");
p.add(cb);

TextField<String> txt = new TextField<String>();
txt.setName("value");
txt.setFieldLabel("Test2");
p.add(txt);

final FormBinding binding = new FormBinding(p);
binding.addFieldBinding(new SimpleComboBoxFieldBinding(cb, "value") {

/*
* (non-Javadoc)
*
* @seecom.extjs.gxt.ui.client.binding.SimpleComboBoxFieldBinding#
* onConvertModelValue(java.lang.Object)
*/
@Override
protected Object onConvertModelValue(Object value) {
// TODO Auto-generated method stub

Object o = super.onConvertModelValue(value);
if (o == null) {
simpleComboBox.add((String) value);
}

return super.onConvertModelValue(value);
}

});

binding.autoBind();

final ListStore<BaseModelData> store = new ListStore<BaseModelData>();
store.setMonitorChanges(true);
BaseModelData data = new BaseModelData();
data.set("value", "aaa");
store.add(data);
data = new BaseModelData();
data.set("value", "bbbbbbb");
store.add(data);

binding.setStore(store);

Button btn = new Button("Test");
p.addButton(btn);

btn.addSelectionListener(new SelectionListener<ButtonEvent>() {

@Override
public void componentSelected(ButtonEvent ce) {
// TODO Auto-generated method stub
if (store.getModifiedRecords().size() == 0) {
Info.display("the modified record count 0", "error");
store.rejectChanges();
return;
}
store.commitChanges();

}
});

List<ColumnConfig> cfg = new ArrayList<ColumnConfig>();
cfg.add(new ColumnConfig("value", "Value", 100));

ColumnModel cm = new ColumnModel(cfg);

Grid<BaseModelData> g = new Grid<BaseModelData>(store, cm);

g.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
g.getSelectionModel().addSelectionChangedListener(new SelectionChangedListener<BaseModelData>() {

@Override
public void selectionChanged(SelectionChangedEvent<BaseModelData> se) {
// TODO Auto-generated method stub
binding.bind(se.getSelectedItem());

}
});

c.add(g, new RowData(1, 1));

port.add(c);

RootPanel.get().add(port);

}

}






Oh, one more thing. when I run my own project in Chrome, here is an display issue like this:
http://weiming.hangonline.com/bug.JPG
it's a normal TabPanel with an Icon and chinese title. you can see, the icon's position is wrong.
my Chrome version is 3.0.195.1 IE and Firefox works fine by the way.

sven
29 Jul 2009, 1:20 AM
You need to defer the buttonlogic.

flyinghang
29 Jul 2009, 6:35 AM
the TextField is ok, whatever you type in the TextField will send back to grid after click the button. with or without any delay.

why TextField and the Combobox's behavior are different?

look forward to your response, thx!

sven
29 Jul 2009, 6:41 AM
ComboBox is a complex widget with has more than one element. Blur/Focus is far more complex for this. That is why there can be a delay until a real blur is recognized.

flyinghang
29 Jul 2009, 6:46 PM
sven,

Thank you for your reply, it's very helpful. :)

and how do you think about the incorrect position of icon on the TabPanel? that has bothered me for a long time.....

Arno.Nyhm
30 Jul 2009, 6:34 AM
Thank you for your reply, it's very helpful. :)

can you post your solution?

i changed the button listener to this but still is not working. it only saves the value if you select a value from the dropdown list of the combobox.


btn.addSelectionListener(new SelectionListener<ButtonEvent>() {

@Override
public void componentSelected(ButtonEvent ce) {

DeferredCommand.addCommand(new Command() { // <-- new line

public void execute() { // <-- new line

if (store.getModifiedRecords().size() == 0) {
Info.display("the modified record count 0", "error");
store.rejectChanges();
return;
}
store.commitChanges();
} // <-- new line
}); // <-- new line
}
});

flyinghang
30 Jul 2009, 5:56 PM
can you post your solution?

i changed the button listener to this but still is not working. it only saves the value if you select a value from the dropdown list of the combobox.


btn.addSelectionListener(new SelectionListener<ButtonEvent>() {

@Override
public void componentSelected(ButtonEvent ce) {

DeferredCommand.addCommand(new Command() { // <-- new line

public void execute() { // <-- new line

if (store.getModifiedRecords().size() == 0) {
Info.display("the modified record count 0", "error");
store.rejectChanges();
return;
}
store.commitChanges();
} // <-- new line
}); // <-- new line
}
});




Actually, I did try DefferedCommand, but failed. and then I tried Timer like this:



@Override
public void componentSelected(ButtonEvent ce) {
// TODO Auto-generated method stub
Timer t = new Timer() {

@Override
public void run() {
if (store.getModifiedRecords().size() == 0) {
Info.display("the modified record count 0", "error");
store.rejectChanges();
return;
}
store.commitChanges();

}

};
t.schedule(500);
}




Still failed.... so I gived up. it's only sending back value when select item in the drop down list.

so , in general, I don't have any solution neither. Could anyone post a code snippet that works?

mabco
3 Oct 2009, 7:21 PM
Sven, since you suggested the solution, can you please help a few users out on this? If you could please describe the cause of this problem with more than a few-word, vague sentence, that would be helpful too. I have no clue why users of this API should have to worry about this:

"ComboBox is a complex widget with has more than one element. Blur/Focus is far more complex for this. That is why there can be a delay until a real blur is recognized."

This is a GXT implementation detail. Users of the GXT API should not have to have knowledge of the fact that ComboBox is a "complex" widget or not. If a user of my application changes the value in a ComboBox, the API implementation should deal with whatever it takes to get that value into the bean that is bound to the form. It just blows me away the hoops I have to jump through to use this API! Pardon my attitude but it's very frustrating.

sven
4 Oct 2009, 8:50 AM
We already changed a couple of things internly to make this better work without knowing anything how browsers work.

However the Binding works with the changeevent. So this event has to fire first before you can do any other action.

If BaseModel is used, the the model fires an update event. After this event you can be sure, that the value is updated.