Skip to content

Commit

Permalink
fix: Use JS equals to check whether property value is changed (#11192)…
Browse files Browse the repository at this point in the history
… (CP: 2.6) (#11287)

Fixes #11175

Co-authored-by: Denis <denis@vaadin.com>
Co-authored-by: Pekka Hyvönen <pekka@vaadin.com>
  • Loading branch information
3 people committed Jun 18, 2021
1 parent 2ffe00f commit a8b8801
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 4 deletions.
40 changes: 40 additions & 0 deletions flow-client/src/main/java/com/vaadin/client/WidgetUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.vaadin.client;

import java.util.Objects;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;

Expand Down Expand Up @@ -319,4 +321,42 @@ public static native String stringify(JsonObject payload) /*-{
return value;
});
}-*/;

/**
* Checks whether the objects are equal either as Java objects (considering
* types and Java {@link Object#equals(Object)} method) or as JS values.
*
* @param obj1
* an object
*
* @param obj2
* an object to be compared with {@code a} for deep equality
* @return {@code true} if the arguments are equal to each other and
* {@code false} otherwise
*
* @see #equalsInJS(Object, Object)
*/
public static boolean equals(Object obj1, Object obj2) {
return Objects.equals(obj1, obj2) || equalsInJS(obj1, obj2);
}

/**
* Checks whether the objects are equal as JS values.
* <p>
* This check ignores object types and checks the values via JS {@code ==}.
* E.g. it means that an empty string equals to {@code 0}.
*
* @param obj1
* an object
*
* @param obj2
* an object to be compared with {@code a} for deep equality
* @return {@code true} if the arguments are equal via JS {@code ==} to each
* other and {@code false} otherwise
*/
public static native boolean equalsInJS(Object obj1, Object obj2)
/*-{
return obj1==obj2;
}-*/;

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package com.vaadin.client.flow.binding;

import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;

Expand Down Expand Up @@ -733,7 +732,7 @@ private void updateProperty(MapProperty mapProperty, Element element) {
// which are updated on the client side, e.g. when synchronizing
// properties to the server (won't work for readonly properties).
if (WidgetUtil.isUndefined(domValue)
|| !Objects.equals(domValue, treeValue)) {
|| !WidgetUtil.equals(domValue, treeValue)) {
Reactive.runWithComputation(null,
() -> WidgetUtil.setJsProperty(element, name,
PolymerUtils.createModelTree(treeValue)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,21 @@ public void testBindExistingProperty() {
assertEquals("foo", element.getTitle());
}

public void testBindExistingPropertyWithDifferentType() {
//set number as a property value for DOM elememnt
double value= setNumberValue(element, "bar");

// set string as a StateTree property value
properties.getProperty("bar").setValue(""+value);

Binder.bind(node, element);

Reactive.flush();

// the type should not be changed
assertEquals("number", getPropertyType(element, "bar"));
}

public void testBindNewProperty() {
Binder.bind(node, element);

Expand Down Expand Up @@ -1617,7 +1632,6 @@ public void testBindHiddenElement_stateNodeChangesVisibility_elementStaysHidden(
assertEquals("", element.getStyle().getDisplay());
}


/**
* The element is in shadowroot and state node is hidden. The element gets
* attribute "hidden" and "display: none".
Expand Down Expand Up @@ -1658,7 +1672,6 @@ public void testBindHiddenElement_elementInShadowRootAndHasInitialDisplayPropert
assertEquals("inline-block", element.getStyle().getDisplay());
}


/**
* The StateNode is visible (the visibility is true).
*
Expand Down Expand Up @@ -1962,4 +1975,15 @@ private native void initPolymer(Element element)
}
}-*/;

private native String getPropertyType(Object obj, String name)
/*-{
return typeof obj[name];
}-*/;

private native double setNumberValue(Object obj, String name)
/*-{
obj[name] =2;
return 2;
}-*/;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { LitElement, html } from "lit-element";

export class InjectedTemplate extends LitElement {
static get properties() {
return {
value: { type: Number}
};
}
render() {
return html`
<div>Injected Template</div>
`;
}
}
customElements.define("injected-lit-template", InjectedTemplate);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { LitElement, html } from "lit-element";
import "./InjectedTemplate.js";

export class InjectingTemplate extends LitElement {
render() {
return html`
<div id='container'></div>
<injected-lit-template value="1.0" id='injected' ></injected-lit-template>
<button id='show-type' @click="${e => this._addClientSideChild()}">Show type</button>
`;
}

_addClientSideChild() {
let element = document.createElement("div");
element.innerHTML = typeof this.shadowRoot.querySelector('#injected').value;
element.id='type-info';
this.shadowRoot.querySelector('#container').appendChild(element);
}
}
customElements.define("injecting-lit-template", InjectingTemplate);
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.vaadin.flow.uitest.ui.littemplate;

import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.littemplate.LitTemplate;

@Tag("injected-lit-template")
@JsModule("./lit/InjectedTemplate.js")
public class InjectedTemplateView extends LitTemplate {

public InjectedTemplateView() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.vaadin.flow.uitest.ui.littemplate;

import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.littemplate.LitTemplate;
import com.vaadin.flow.component.template.Id;
import com.vaadin.flow.router.Route;

@Route(value = "com.vaadin.flow.uitest.ui.littemplate.InjectingTemplateView")
@Tag("injecting-lit-template")
@JsModule("./lit/InjectingTemplate.js")
public class InjectingTemplateView extends LitTemplate {

@Id("injected")
private InjectedTemplateView view;

public InjectingTemplateView() {
setId("injecting");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2000-2021 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.flow.uitest.ui.littemplate;

import org.junit.Assert;
import org.junit.Test;

import com.vaadin.flow.testutil.ChromeBrowserTest;
import com.vaadin.testbench.TestBenchElement;

public class InjectingTemplateIT extends ChromeBrowserTest {

@Test
public void mapTemplateViaIdWithNumberProperty_propertyTypeIsNotChangedAfterBidning() {
open();

TestBenchElement template = $(TestBenchElement.class).id("injecting");
template.$(TestBenchElement.class).id("show-type").click();

TestBenchElement container = template.$(TestBenchElement.class)
.id("container");
Assert.assertEquals("number", container.getText());
}
}

0 comments on commit a8b8801

Please sign in to comment.