2

I created a Vaadin Flow v22 Component wrapping the UI5 MultiComboBox Webcomponent:

@Tag("ui5-multi-combobox")
@NpmPackage(value = "@ui5/webcomponents", version = "^1.1.2")
@JsModule("@ui5/webcomponents/dist/MultiComboBox.js")
@JsModule("@ui5/webcomponents/dist/features/InputElementsFormSupport.js")
public class Ui5MultiComboBox extends Component implements HasComponents, HasLabel, HasSize {
    …
    public void setPlaceholder(String placeholder) {
        this.getElement().setProperty("placeholder", placeholder);
    }
    …
    @DomEvent("selection-change")
    public static class SelectionChangeEvent extends ComponentEvent<Ui5MultiComboBox> {
        public SelectionChangeEvent(Ui5MultiComboBox source, boolean fromClient,
                @EventData("element.placeholder") String placeholder,
                @EventData("event.bubbles") boolean bubbles,
                @EventData("event.items") JsonArray itemsa) {
            super(source, fromClient);
            LOGGER.info("Ui5MultiComboBoxSelectionChangeEvent: placeholder=" + placeholder);
            LOGGER.info("Ui5MultiComboBoxSelectionChangeEvent: bubbles=" + bubbles);
            LOGGER.info("Ui5MultiComboBoxSelectionChangeEvent: itemsa=" + itemsa);
        }
    }
    …
    public Registration addSelectionChangeListener(ComponentEventListener<SelectionChangeEvent> listener) {
        return addListener(SelectionChangeEvent.class, listener);
    }
}

I then use the Vaadin Component in my Vaadin View:

…
Ui5MultiComboBox multiCombo1 = new Ui5MultiComboBox();
multiCombo1.setPlaceholder("Enter or pick items");
multiCombo1.addSelectionChangeListener(e -> {
    LOGGER.info("View: Selection Changed Listener ...");
});

getContent().add(multiCombo1);

// add items:
for (ItemData d : data) {
    Ui5MultiComboBoxItem multiComboItem = new Ui5MultiComboBoxItem();
    multiComboItem.setText(d.text);
    multiComboItem.setSelected(d.selected);

    multiCombo1.add(multiComboItem);
}

I run my Application (in Crome) and it renders as expected. When I remove one of the Ui5MultiComboBoxItem, my Listener fires as expected.

The problem is that the Listener does not get access to the @EventData("event.items") JsonArray itemsa.

Console shows null for that itemsa variable, while accessing more simple @EventData like "element.placeholder" or "event.bubbles" perfectly works:

Ui5MultiComboBoxSelectionChangeEvent: placeholder=Enter or pick items
Ui5MultiComboBoxSelectionChangeEvent: bubbles=true
Ui5MultiComboBoxSelectionChangeEvent: itemsa=null
View: Selection Changed Listener ...

I've also used:

@EventData("event.detail") JsonArray itemsa
@EventData("event.detail.items") JsonArray itemsa
@EventData("event.detail") JsonObject itemsa
@EventData("event.detail.items") JsonObject itemsa
@EventData("event.detail") String itemsa
@EventData("event.detail.items") String itemsa
@EventData("event.detail") Object itemsa
@EventData("event.detail.items") Object itemsa

but all these raise an error in Chrome Console:

(String) : Message JsonObject contained a dom node reference which should not be sent to the server and can cause a cyclic dependecy.

The typo in "dependecy" might give a hint who is issuing that error message.

Here's the UI5 Web Component Description: MultiComboBox

Any help highly appreciated!

Gork B
  • 21
  • 2
  • Is the `items` property something that can be serialized? – ollitietavainen Feb 10 '22 at 09:17
  • MultiComboBox is a 3rd party component, so I forwarded this question to the OpenUI5 Slack. – Gork B Feb 12 '22 at 17:24
  • Is the requirement to serialize data sent to the server specified in some standard? or is it required just by the the Vaadin platform? I mean: will fixing github.com/vaadin/flow/issues/4214 just remove the blocking, or will receiving a HTMLElement then be possible? – Gork B Feb 12 '22 at 17:27
  • I think the same limitations apply as with https://vaadin.com/docs/latest/flow/element-api/client-server-rpc/#clientcallable-annotation : The supported argument types are: * boolean , int, double, their boxed types (Boolean , Integer, Double) * String * JsonValue * enumeration type which is addressed via a string value from the client-side JavaScript * TemplateModel property types – ollitietavainen Feb 13 '22 at 09:54

1 Answers1

1

You need to know in detail how the web component you are integrating has implemented the detail. I take one of my own projects as example here. So lets say I have web component tab-sheet, where I fire custom even called tab-changed. I need some metadata to be delivered to server side in the event, so I compose JSON object details with couple of properties.

  selectedChanged(e: CustomEvent) {
    const page = e.detail.value;
    const tab = this.getTab(page);
    this._doSelectTab(page);
    const details : JSON = <JSON><unknown>{
      "index": page,
      "caption": this.getTabCaption(tab),
      "tab": tab
    }
    const event = new CustomEvent('tab-changed', {
        detail: details,
        composed: true,
        cancelable: true,
        bubbles: true       
    });
    this.dispatchEvent(event);
  }

The full implementation of the component is here: https://github.com/TatuLund/TabSheet/blob/master/src/main/resources/META-INF/resources/frontend/tab-sheet.ts

Now, I want to observe this event on Java class that is the server side representation of the component.

I use @DomEvent for that and in constructor of the event class, I decipher the JSON using @EventData("event.detail"), which now contains the JSON object I composed.

    @DomEvent("tab-changed")
    public static class TabChangedEvent<R extends TabSheet> extends ComponentEvent<TabSheet> {
        private int index;
        private TabSheet source;
        private String caption;
        private String tab;

        public TabChangedEvent(TabSheet source, boolean fromClient, @EventData("event.detail") JsonObject details) {
            super(source, fromClient);
            this.index = (int) details.getNumber("index");
            this.tab = details.getString("tab");
            this.caption = details.getString("caption");
            this.source = source;
        }
    ...
    }

The full code is here: https://github.com/TatuLund/TabSheet/blob/master/src/main/java/org/vaadin/addons/tatu/TabSheet.java

Tatu Lund
  • 9,949
  • 1
  • 12
  • 26
  • Thanks for your non-trivial example (first one I see except my own ;-) As mentioned in my original post, I've already tried `@EventData("event.detail") JsonObject itemsa` before and this ended in the behavior described in this open issue: https://github.com/vaadin/flow/issues/4214 Same message in the chrome console, including the mentioned typo („dependecy“), then application is frozen. – Gork B Feb 09 '22 at 19:12