diff options
5 files changed, 185 insertions, 0 deletions
diff --git a/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java b/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java index 6510b5305a..81126f3189 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java +++ b/server/src/main/java/com/vaadin/ui/AbstractSingleSelect.java @@ -39,6 +39,8 @@ import com.vaadin.ui.declarative.DesignContext; import com.vaadin.ui.declarative.DesignException; import com.vaadin.util.ReflectTools; +import elemental.json.Json; + /** * An abstract base class for listing components that only support single * selection and no lazy loading of data items. @@ -241,6 +243,12 @@ public abstract class AbstractSingleSelect<T> extends AbstractListing<T> } doSetSelectedKey(key); + + // Update diffstate so that a change will be sent to the client if the + // selection is changed to its original value + updateDiffstate("selectedItemKey", + key == null ? Json.createNull() : Json.create(key)); + fireEvent(new SingleSelectionEvent<>(AbstractSingleSelect.this, true)); } diff --git a/server/src/main/java/com/vaadin/ui/ComboBox.java b/server/src/main/java/com/vaadin/ui/ComboBox.java index 22e6a698eb..b958ca9c32 100644 --- a/server/src/main/java/com/vaadin/ui/ComboBox.java +++ b/server/src/main/java/com/vaadin/ui/ComboBox.java @@ -52,6 +52,7 @@ import com.vaadin.ui.declarative.DesignAttributeHandler; import com.vaadin.ui.declarative.DesignContext; import com.vaadin.ui.declarative.DesignFormatter; +import elemental.json.Json; import elemental.json.JsonObject; /** @@ -670,4 +671,21 @@ public class ComboBox<T> extends AbstractSingleSelect<T> // ComboBox. return (DataCommunicator<T, String>) super.getDataCommunicator(); } + + @Override + protected void setSelectedFromClient(String key) { + super.setSelectedFromClient(key); + + /* + * The client side for combo box always expects a state change for + * selectedItemKey after it has sent a selection change. This means that + * we must store a value in the diffstate that guarantees that a new + * value will be sent, regardless of what the value actually is at the + * time when changes are sent. + * + * Keys are always strings (or null), so using a non-string type will + * always trigger a diff mismatch and a resend. + */ + updateDiffstate("selectedItemKey", Json.create(0)); + } } diff --git a/server/src/test/java/com/vaadin/ui/ComboBoxTest.java b/server/src/test/java/com/vaadin/ui/ComboBoxTest.java new file mode 100644 index 0000000000..36b29fdd7a --- /dev/null +++ b/server/src/test/java/com/vaadin/ui/ComboBoxTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui; + +import org.junit.Test; + +import com.vaadin.shared.data.selection.SelectionServerRpc; +import com.vaadin.tests.util.MockUI; + +public class ComboBoxTest { + + @Test + public void testResetValue() { + ComboBox<String> comboBox = new ComboBox<>(); + comboBox.setItems("one", "two"); + + // Reset value whenever it changes (in a real case, this listener would + // do something with the selected value before discarding it) + comboBox.addValueChangeListener(e -> comboBox.setValue(null)); + + // "Attach" the component and initialize diffstate + new MockUI().setContent(comboBox); + ComponentTest.syncToClient(comboBox); + + // Emulate selection of "one" + String oneKey = comboBox.getDataCommunicator().getKeyMapper() + .key("one"); + ComponentTest.getRpcProxy(comboBox, SelectionServerRpc.class) + .select(oneKey); + + ComponentTest.assertEncodedStateProperties(comboBox, + "Selection change done by the listener should be sent to the client", + "selectedItemKey"); + } +} diff --git a/uitest/src/main/java/com/vaadin/tests/components/combobox/ComboBoxAutoresetValue.java b/uitest/src/main/java/com/vaadin/tests/components/combobox/ComboBoxAutoresetValue.java new file mode 100644 index 0000000000..c957cc0673 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/components/combobox/ComboBoxAutoresetValue.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.combobox; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.ComboBox; + +public class ComboBoxAutoresetValue extends AbstractTestUIWithLog { + + public static final String RESET = "Reset"; + public static final String CHANGE = "Change to something else"; + public static final String SOMETHING = "Something else"; + + @Override + protected void setup(VaadinRequest request) { + ComboBox<String> comboBox = new ComboBox<>(); + comboBox.setItems(RESET, CHANGE, SOMETHING); + comboBox.addValueChangeListener(e -> { + String value = e.getValue(); + log("Value changed to " + value); + + if (e.isUserOriginated()) { + if (RESET.equals(value)) { + e.getSource().setValue(null); + } else if (CHANGE.equals(value)) { + e.getSource().setValue(SOMETHING); + } + } + }); + addComponent(comboBox); + } + + @Override + public String getDescription() { + return "Changing the ComboBox value in its own value change listener should work"; + } + +} diff --git a/uitest/src/test/java/com/vaadin/tests/components/combobox/ComboBoxAutoresetValueTest.java b/uitest/src/test/java/com/vaadin/tests/components/combobox/ComboBoxAutoresetValueTest.java new file mode 100644 index 0000000000..b3a34b7edb --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/combobox/ComboBoxAutoresetValueTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.combobox; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.customelements.ComboBoxElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class ComboBoxAutoresetValueTest extends SingleBrowserTest { + + @Test + public void testValueChanges() { + openTestURL(); + + ComboBoxElement comboBox = $(ComboBoxElement.class).first(); + + Assert.assertEquals("", comboBox.getValue()); + + comboBox.selectByText(ComboBoxAutoresetValue.RESET); + + assertLogChange(1, ComboBoxAutoresetValue.RESET, 1); + assertLogChange(2, null, 0); + Assert.assertEquals("", comboBox.getValue()); + + comboBox.selectByText(ComboBoxAutoresetValue.CHANGE); + assertLogChange(3, ComboBoxAutoresetValue.CHANGE, 1); + assertLogChange(4, ComboBoxAutoresetValue.SOMETHING, 0); + Assert.assertEquals(ComboBoxAutoresetValue.SOMETHING, + comboBox.getValue()); + + comboBox.selectByText(ComboBoxAutoresetValue.SOMETHING); + // No new log items + assertLogChange(4, ComboBoxAutoresetValue.SOMETHING, 0); + Assert.assertEquals(ComboBoxAutoresetValue.SOMETHING, + comboBox.getValue()); + } + + private void assertLogChange(int sequenceNumber, String expectedValue, + int rowIndex) { + Assert.assertEquals( + sequenceNumber + ". Value changed to " + expectedValue, + getLogRow(rowIndex)); + } +} |