Set property of webcomponent without JS

I integrated [Paper Speed Dial]
(https://www.webcomponents.org/element/@cwmr/paper-fab-speed-dial/elements/paper-fab-speed-dial) and wrote an adapter component. The Speed Dial is a round absolute positioned menu. When clicking a menu item, I want to get notified on server side and close the menu.

The click listener works like expected and also closing it works.
But I changed the opened state of the component by

getElement().executeJs("this.opened=false");

How can I achieve that without executeJs - this seems not to be not the preferred way?

I also tried:

getElement().setProperty("opened", false);
getElement().getShadowRoot().ifPresent(root -> root.getHost().setProperty("opened", false));

Full source code is available here:
github.com/TobseF/CleanCodeDeveloperJournal/[…]
SpeedDial.java

Any feedback is welcome, because I want to the webcomponent binding in the correct way

@Tag("paper-fab-speed-dial")
@NpmPackage(value = "@cwmr/paper-fab-speed-dial", version = "3.0.0")
@JsModule("@cwmr/paper-fab-speed-dial/paper-fab-speed-dial.js")
public class SpeedDial extends Component  {

    public SpeedDialAction addMenuItem(String item, Icon icon) {
        SpeedDialAction speedDialAction = new SpeedDialAction(item, icon);
        getElement().appendChild(speedDialAction.getElement());
        return speedDialAction;
    }
    
    public void close() {
        getElement().executeJs("this.opened=false");
        getElement().setProperty("opened", false);
        getElement().getShadowRoot().ifPresent(root -> root.getHost().setProperty("opened", false));
    }

    public void open() {
        getElement().executeJs("this.opened=true");
    }
    
}
getElement().executeJs("this.opened=false");
getElement().setProperty("opened", false);

Afaik these 2 lines should be basically equivalent. setProperty should work for this. If it doesn’t, but executeJs does then I think it might be some timing issue since afaik executeJs calls are executed later.

You can take a look at the sources of the Vaadin components and see that setProperty is also used there for basic property changes like this. For example [setDisabled()]
(https://github.com/vaadin/vaadin-button-flow/blob/master/vaadin-button-flow/src/main/java/com/vaadin/flow/component/button/GeneratedVaadinButton.java#L203-L205) in Vaadin Button.

See also [setOpened()]
(https://github.com/vaadin/vaadin-combo-box-flow/blob/master/vaadin-combo-box-flow/src/main/java/com/vaadin/flow/component/combobox/GeneratedVaadinComboBox.java#L448) and [open()]
(https://github.com/vaadin/vaadin-combo-box-flow/blob/master/vaadin-combo-box-flow/src/main/java/com/vaadin/flow/component/combobox/GeneratedVaadinComboBox.java#L1140) in Vaadin ComboBox.

The approach for setting and reading component properties when creating Java API for a component is also documented here: https://vaadin.com/docs/v14/flow/web-components/creating-java-api-for-a-web-component.html#setting-and-reading-properties

You probably also want to make sure that the opened property is synchronized to the server too so that if it changes on the client, you also get the new state of it on the server.

Actually that might be the problem that server still thinks that opened is false (if the opening was triggered from client side and not from Java code). In that case setProperty("opened", false) would not do anything if server thinks that it is already false.

This part is about that https://vaadin.com/docs/v14/flow/web-components/creating-java-api-for-a-web-component.html#synchronizing-the-value but the relevant part for this case is actually a bit hidden since here we don’t care about a “value” property but another property (opened). If we were interested in the “value” property and were extending AbstractSinglePropertyField like suggested then the value property synchronization would be handled automatically, but for other properties you still need to set up the synchronization. The relevant part here is the last “NOTE” block on gray background:

Some web components also update other properties that are not related to HasValue. [Creating A Simple Component Using the Element API]
(https://vaadin.com/docs/v14/flow/creating-components/tutorial-component-basic.html) describes how you can use the @Synchronize annotation to synchronize property values without automatically firing a value change event.

Look here: https://vaadin.com/docs/v14/flow/creating-components/tutorial-component-basic.html#adding-an-api

You probably need to add a getter like:

@Synchronize("opened-changed")
public boolean isOpened() {
    return getElement().getProperty("opened", false);
}

Here’s a similar but slightly different example from ComboBox code: https://github.com/vaadin/vaadin-combo-box-flow/blob/master/vaadin-combo-box-flow/src/main/java/com/vaadin/flow/component/combobox/GeneratedVaadinComboBox.java#L432

Or you can make it protected if you like.

\u0000Tank’s a lot for the detailed answer.\n\nThe\n@Synchronize(\"opened-changed\")\ndoes it job. Now it works like expected \uD83D\uDC4D