diff --git a/flow-client/src/main/java/com/vaadin/client/flow/binding/SimpleElementBindingStrategy.java b/flow-client/src/main/java/com/vaadin/client/flow/binding/SimpleElementBindingStrategy.java
index 6b1c8455251..d263ed50bdb 100644
--- a/flow-client/src/main/java/com/vaadin/client/flow/binding/SimpleElementBindingStrategy.java
+++ b/flow-client/src/main/java/com/vaadin/client/flow/binding/SimpleElementBindingStrategy.java
@@ -24,6 +24,7 @@
import com.vaadin.client.Command;
import com.vaadin.client.Console;
import com.vaadin.client.ExistingElementMap;
+import com.vaadin.client.InitialPropertiesHandler;
import com.vaadin.client.PolymerUtils;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.flow.ConstantPool;
@@ -61,7 +62,6 @@
import elemental.json.JsonObject;
import elemental.json.JsonType;
import elemental.json.JsonValue;
-
import jsinterop.annotations.JsFunction;
/**
@@ -284,9 +284,9 @@ private native void bindPolymerModelProperties(StateNode node,
private native void hookUpPolymerElement(StateNode node, Element element)
/*-{
var self = this;
-
+
var originalPropertiesChanged = element._propertiesChanged;
-
+
if (originalPropertiesChanged) {
element._propertiesChanged = function (currentProps, changedProps, oldProps) {
$entry(function () {
@@ -295,16 +295,16 @@ private native void hookUpPolymerElement(StateNode node, Element element)
originalPropertiesChanged.apply(this, arguments);
};
}
-
-
+
+
var tree = node.@com.vaadin.client.flow.StateNode::getTree()();
-
+
var originalReady = element.ready;
-
+
element.ready = function (){
originalReady.apply(this, arguments);
@com.vaadin.client.PolymerUtils::fireReadyEvent(*)(element);
-
+
// The _propertiesChanged method which is replaced above for the element
// doesn't do anything for items in dom-repeat.
// Instead it's called with some meaningful info for the dom-repeat
element.
@@ -313,7 +313,7 @@ private native void hookUpPolymerElement(StateNode node, Element element)
// which changes this method for any dom-repeat instance.
var replaceDomRepeatPropertyChange = function(){
var domRepeat = element.root.querySelector('dom-repeat');
-
+
if ( domRepeat ){
// If the dom-repeat
element is in the DOM then
// this method should not be executed anymore. The logic below will replace
@@ -327,12 +327,12 @@ private native void hookUpPolymerElement(StateNode node, Element element)
// if dom-repeat is found => replace _propertiesChanged method in the prototype and mark it as replaced.
if ( !domRepeat.constructor.prototype.$propChangedModified){
domRepeat.constructor.prototype.$propChangedModified = true;
-
+
var changed = domRepeat.constructor.prototype._propertiesChanged;
-
+
domRepeat.constructor.prototype._propertiesChanged = function(currentProps, changedProps, oldProps){
changed.apply(this, arguments);
-
+
var props = Object.getOwnPropertyNames(changedProps);
var items = "items.";
for(i=0; ifalse initially.
// in this case dom-repeat is not yet in the DOM tree until dom-if becomes true
@@ -389,7 +389,7 @@ private native void hookUpPolymerElement(StateNode node, Element element)
element.addEventListener('dom-change',replaceDomRepeatPropertyChange);
}
}
-
+
}-*/;
private static void handleListItemPropertyChange(double nodeId,
@@ -846,6 +846,9 @@ private void appendVirtualChild(BindingContext context, StateNode node,
return;
}
+ InitialPropertiesHandler initialPropertiesHandler = node.getTree()
+ .getRegistry().getInitialPropertiesHandler();
+
assert context.htmlNode instanceof Element : "Unexpected html node. The node is supposed to be a custom element";
if (NodeProperties.INJECT_BY_ID.equals(type)) {
String id = object.getString(NodeProperties.PAYLOAD);
@@ -864,6 +867,10 @@ private void appendVirtualChild(BindingContext context, StateNode node,
.getDomElementById(context.htmlNode, id);
if (verifyAttachedElement(existingElement, node, id, address,
context)) {
+ if (!reactivePhase) {
+ initialPropertiesHandler.nodeRegistered(node);
+ initialPropertiesHandler.flushPropertyUpdates();
+ }
node.setDomNode(existingElement);
context.binderContext.createAndBind(node);
}
@@ -886,6 +893,10 @@ private void appendVirtualChild(BindingContext context, StateNode node,
if (verifyAttachedElement(customElement, node, null, address,
context)) {
+ if (!reactivePhase) {
+ initialPropertiesHandler.nodeRegistered(node);
+ initialPropertiesHandler.flushPropertyUpdates();
+ }
node.setDomNode(customElement);
context.binderContext.createAndBind(node);
}
diff --git a/flow-client/src/test-gwt/java/com/vaadin/client/flow/GwtBasicElementBinderTest.java b/flow-client/src/test-gwt/java/com/vaadin/client/flow/GwtBasicElementBinderTest.java
index 452e4693941..52a3596d133 100644
--- a/flow-client/src/test-gwt/java/com/vaadin/client/flow/GwtBasicElementBinderTest.java
+++ b/flow-client/src/test-gwt/java/com/vaadin/client/flow/GwtBasicElementBinderTest.java
@@ -64,7 +64,7 @@ protected void gwtSetUp() throws Exception {
titleProperty = properties.getProperty("title");
idAttribute = attributes.getProperty("id");
- nextId = node.getId() + 1;
+ nextId = node.getId() + 2;
element = Browser.getDocument().createElement("div");
}
@@ -246,6 +246,7 @@ public void testRemoveAttribute() {
private StateNode createChildNode(String id, String tag) {
StateNode childNode = new StateNode(nextId++, node.getTree());
+ node.getTree().registerNode(childNode);
childNode.getMap(NodeFeatures.ELEMENT_DATA)
.getProperty(NodeProperties.TAG).setValue(tag);
@@ -1278,6 +1279,10 @@ public void testBindVirtualChild_withCorrespondingElementInShadowRoot_byId() {
String childId = "childElement";
StateNode childNode = createChildNode(childId, element.getTagName());
+ NodeMap properties = childNode.getMap(NodeFeatures.ELEMENT_PROPERTIES);
+ MapProperty fooProperty = properties.getProperty("foo");
+ fooProperty.setValue("bar");
+
Binder.bind(node, element);
addVirtualChild(node, childNode, NodeProperties.INJECT_BY_ID,
@@ -1326,6 +1331,10 @@ public void testBindVirtualChild_withDeferredElementInShadowRoot_byId() {
String tag = element.getTagName();
StateNode childNode = createChildNode(childId, tag);
+ NodeMap properties = childNode.getMap(NodeFeatures.ELEMENT_PROPERTIES);
+ MapProperty fooProperty = properties.getProperty("foo");
+ fooProperty.setValue("bar");
+
addVirtualChild(node, childNode, NodeProperties.INJECT_BY_ID,
Json.create(childId));
@@ -1352,9 +1361,20 @@ public void testBindVirtualChild_withDeferredElementInShadowRoot_byId() {
Element addressedElement = createAndAppendElementToShadowRoot(
shadowRoot, childId, tag);
+ // add flush listener which register the property to revert its initial
+ // value back if it has been changed during binding "from the client
+ // side" and do update the property emulating client side update
+ // The property value should be reverted back in the end
+ Reactive.addFlushListener(() -> {
+ tree.getRegistry().getInitialPropertiesHandler()
+ .handlePropertyUpdate(fooProperty);
+ fooProperty.setValue("baz");
+ });
+
PolymerUtils.fireReadyEvent(element);
- Reactive.flush();
+ // the property value should be the same as initially
+ assertEquals("bar", fooProperty.getValue());
expectedAfterBindingFeatures.forEach(expectedFeature -> assertTrue(
"Child node should have all features from list "
@@ -1381,6 +1401,10 @@ public void testBindVirtualChild_withDeferredElementInShadowRoot_byIndicesPath()
String childId = "childElement";
StateNode childNode = createChildNode(childId, element.getTagName());
+ NodeMap properties = childNode.getMap(NodeFeatures.ELEMENT_PROPERTIES);
+ MapProperty fooProperty = properties.getProperty("foo");
+ fooProperty.setValue("bar");
+
WidgetUtil.setJsProperty(element, "ready", NativeFunction.create(""));
Binder.bind(node, element);
@@ -1411,9 +1435,20 @@ public void testBindVirtualChild_withDeferredElementInShadowRoot_byIndicesPath()
Element addressedElement = createAndAppendElementToShadowRoot(
shadowRoot, childId, element.getTagName());
+ // add flush listener which register the property to revert its initial
+ // value back if it has been changed during binding "from the client
+ // side" and do update the property emulating client side update
+ // The property value should be reverted back in the end
+ Reactive.addFlushListener(() -> {
+ tree.getRegistry().getInitialPropertiesHandler()
+ .handlePropertyUpdate(fooProperty);
+ fooProperty.setValue("baz");
+ });
+
PolymerUtils.fireReadyEvent(element);
- Reactive.flush();
+ // the property value should be the same as initially
+ assertEquals("bar", fooProperty.getValue());
expectedAfterBindingFeatures.forEach(expectedFeature -> assertTrue(
"Child node should have all features from list "
diff --git a/flow-client/src/test-gwt/java/com/vaadin/client/flow/GwtPropertyElementBinderTest.java b/flow-client/src/test-gwt/java/com/vaadin/client/flow/GwtPropertyElementBinderTest.java
index f72afe08bdc..fe16674807c 100644
--- a/flow-client/src/test-gwt/java/com/vaadin/client/flow/GwtPropertyElementBinderTest.java
+++ b/flow-client/src/test-gwt/java/com/vaadin/client/flow/GwtPropertyElementBinderTest.java
@@ -20,6 +20,7 @@
import com.vaadin.client.ClientEngineTestBase;
import com.vaadin.client.ExistingElementMap;
+import com.vaadin.client.InitialPropertiesHandler;
import com.vaadin.client.Registry;
import com.vaadin.client.flow.binding.Binder;
import com.vaadin.client.flow.collection.JsArray;
@@ -44,6 +45,39 @@
public abstract class GwtPropertyElementBinderTest
extends ClientEngineTestBase {
+ private static class TestRegistry extends Registry {
+ private InitialPropertiesHandler handler = new InitialPropertiesHandler(
+ this);
+
+ private ConstantPool constantPool;
+ private ExistingElementMap existingElementMap;
+
+ TestRegistry(ConstantPool constantPool,
+ ExistingElementMap existingElementMap) {
+ this.constantPool = constantPool;
+ this.existingElementMap = existingElementMap;
+ }
+
+ @Override
+ public ConstantPool getConstantPool() {
+ return constantPool;
+ }
+
+ @Override
+ public ExistingElementMap getExistingElementMap() {
+ return existingElementMap;
+ }
+
+ @Override
+ public InitialPropertiesHandler getInitialPropertiesHandler() {
+ return handler;
+ }
+
+ private void setTree(StateTree tree) {
+ set(StateTree.class, tree);
+ }
+ }
+
protected static class CollectingStateTree extends StateTree {
JsArray collectedNodes = JsCollections.array();
JsArray collectedEventData = JsCollections.array();
@@ -53,17 +87,8 @@ protected static class CollectingStateTree extends StateTree {
public CollectingStateTree(ConstantPool constantPool,
ExistingElementMap existingElementMap) {
- super(new Registry() {
- @Override
- public ConstantPool getConstantPool() {
- return constantPool;
- }
-
- @Override
- public ExistingElementMap getExistingElementMap() {
- return existingElementMap;
- }
- });
+ super(new TestRegistry(constantPool, existingElementMap));
+ ((TestRegistry) getRegistry()).setTree(this);
}
@Override