After a little bit of testing i found out that jQuery change handler (handler for native javascript event of type "change") is added to underlying select element every time method SelectBase.onLoad is called. However this handler is not removed during call to SelectBase.onUnload (which itself calls private method SelectBase.unbindSelectEvents). This leads to undesired behavior that one user interaction fires ChangeEvent many times (as many as SelectBase.onUnload was called).
To fix this issue my advice is to add this one line to method org.gwtbootstrap3.extras.select.client.ui.SelectBase.unbindSelectEvents. This line would be: $wnd.jQuery(e).off("change"); (or we can use constant instead of string literal "change").
I am also providing example source code documenting described issue. Run it with browser's console opened and see the logs. Then wait few seconds to let timers complete. After that click on the Select widget and you can clearly see that ValueChangeHandler is called twice.
Also in the browser' console window we can see that event handler for "change" event is still here even if SelectBase.onUnload was called.
Here is example source code:
EntryPoint class
import org.gwtbootstrap3.extras.select.client.ui.MultipleSelect;
import org.gwtbootstrap3.extras.select.client.ui.Option;
import org.gwtbootstrap3.extras.select.client.ui.Select;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SimplePanel;
public class TestEntrypoint implements EntryPoint {
@Override
public void onModuleLoad() {
RootPanel rp = RootPanel.get("mainDiv");
SimplePanel content = new SimplePanel();
rp.add(content);
Select s = new LoggingSelect();
Option o1 = new Option();
o1.setText("first");
o1.setValue("first");
s.add(o1);
Option o2 = new Option();
o2.setText("second");
o2.setValue("second");
s.add(o2);
s.addValueChangeHandler(new ValueChangeHandler<String>() {
@Override
public void onValueChange(ValueChangeEvent<String> event) {
Window.alert(event.getValue());
}
});
MultipleSelect ms = new LoggingMultipleSelect();
content.setWidget(s);
new Timer() {
@Override
public void run() {
content.setWidget(ms);
}
}.schedule(1_500);
new Timer() {
@Override
public void run() {
content.setWidget(s);
}
}.schedule(3_000);
}
private static class LoggingSelect extends Select {
@Override
protected void onLoad() {
logHandler("Select BEFORE load", getElement());
super.onLoad();
logHandler("Select AFTER load", getElement());
}
@Override
protected void onUnload() {
logHandler("Select BEFORE unload", getElement());
super.onUnload();
logHandler("Select AFTER unload", getElement());
}
}
private static class LoggingMultipleSelect extends MultipleSelect {
@Override
protected void onLoad() {
logHandler("MultipleSelect BEFORE load", getElement());
super.onLoad();
logHandler("MultipleSelect AFTER load", getElement());
}
@Override
protected void onUnload() {
logHandler("MultipleSelect BEFORE unload", getElement());
super.onUnload();
logHandler("MultipleSelect AFTER unload", getElement());
}
}
private static native void logHandler(String logMsg, Element e) /*-{
console.log(logMsg, $wnd.jQuery._data(e, "events"));
}-*/;
}
GWT module
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.8.2//EN"
"http://www.gwtproject.org/doctype/2.8.2/gwt-module.dtd">
<module rename-to="test">
<inherits name="com.google.gwt.user.User" />
<inherits name="org.gwtbootstrap3.GwtBootstrap3" />
<inherits name="org.gwtbootstrap3.extras.select.Select"/>
<entry-point class="com.example.client.TestEntrypoint" />
</module>
After a little bit of testing i found out that jQuery change handler (handler for native javascript event of type "change") is added to underlying select element every time method
SelectBase.onLoad
is called. However this handler is not removed during call toSelectBase.onUnload
(which itself calls private methodSelectBase.unbindSelectEvents
). This leads to undesired behavior that one user interaction firesChangeEvent
many times (as many asSelectBase.onUnload
was called).To fix this issue my advice is to add this one line to method
org.gwtbootstrap3.extras.select.client.ui.SelectBase.unbindSelectEvents
. This line would be:$wnd.jQuery(e).off("change");
(or we can use constant instead of string literal "change").I am also providing example source code documenting described issue. Run it with browser's console opened and see the logs. Then wait few seconds to let timers complete. After that click on the Select widget and you can clearly see that
ValueChangeHandler
is called twice.Also in the browser' console window we can see that event handler for "change" event is still here even if
SelectBase.onUnload
was called.Here is example source code:
EntryPoint class
GWT module
index.html
Maven dependencies