Skip to content

Commit 5804d80

Browse files
committed
prototyping with other client-server-comm improvements that could be useful for Flow (add-ons)
1 parent 37478fd commit 5804d80

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package org.vaadin.addons.velocitycomponent;
2+
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.vaadin.flow.dom.Element;
6+
import com.vaadin.flow.function.SerializableConsumer;
7+
import com.vaadin.flow.shared.Registration;
8+
import elemental.json.JsonType;
9+
import elemental.json.JsonValue;
10+
import org.apache.commons.lang3.StringUtils;
11+
12+
import static java.util.Arrays.stream;
13+
14+
public class VElement {
15+
16+
private static ObjectMapper objectMapper = new ObjectMapper();
17+
18+
private final Element element;
19+
20+
private VElement(Element element) {
21+
this.element = element;
22+
}
23+
24+
public static VElement of(Element element) {
25+
return new VElement(element);
26+
}
27+
28+
/**
29+
* Listen to an event of a specific type. The event type is determined by the class of the event,
30+
* the name can contain optional "Event" postfix which is ignored in DOM event name.
31+
* The event payload is expected to be a JSON object or a string and serialized to the event type
32+
* using Jackson ObjectMapper.
33+
*
34+
* On the client side, the event should be dispatched with a CustomEvent with the detail property.
35+
*
36+
* @param eventType the class of the event
37+
* @param listener the listener to be called when the event is fired
38+
* @return a registration that can be used to remove the listener
39+
* @param <T> the type of the event
40+
*/
41+
public <T> Registration on(Class<T> eventType, SerializableConsumer<T> listener) {
42+
String simpleName = eventType.getSimpleName();
43+
if(simpleName.endsWith("Event")) {
44+
simpleName = simpleName.substring(0, simpleName.length() - 5);
45+
}
46+
String kebabCased = stream(StringUtils.splitByCharacterTypeCamelCase(simpleName))
47+
.map(s -> s.toLowerCase())
48+
.reduce((a, b) -> a + "-" + b).get();
49+
50+
return element.addEventListener(kebabCased, event -> {
51+
JsonValue jsonValue = event.getEventData().get("event.detail");
52+
T value;
53+
if(jsonValue.getType() == JsonType.OBJECT) {
54+
try {
55+
value = objectMapper.readValue(jsonValue.toJson(), eventType);
56+
} catch (Exception e) {
57+
throw new RuntimeException(e);
58+
}
59+
} else {
60+
try {
61+
value = objectMapper.readValue(jsonValue.asString().toString(), eventType);
62+
} catch (JsonProcessingException e) {
63+
throw new RuntimeException(e);
64+
}
65+
}
66+
listener.accept(value);
67+
}).addEventData("event.detail");
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.vaadin.addons.usageexample;
2+
3+
import com.vaadin.flow.component.button.Button;
4+
import com.vaadin.flow.component.html.H1;
5+
import com.vaadin.flow.component.html.Paragraph;
6+
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
7+
import com.vaadin.flow.router.Route;
8+
import org.vaadin.addons.velocitycomponent.VElement;
9+
10+
@Route
11+
public class VElementView extends VerticalLayout {
12+
13+
public record FooBar(String foo, String bar, String car) {}
14+
15+
public VElementView() {
16+
add(new H1("Example to listen DOM events easily!"));
17+
18+
VElement.of(getElement()).on(FooBar.class, event -> {
19+
String bar = event.bar();
20+
add(new Paragraph("Received foo-bar event with detail: " + event));
21+
});
22+
23+
add(new Button("Click me", e -> {
24+
getElement().executeJs("""
25+
this.dispatchEvent(new CustomEvent('foo-bar', {
26+
detail: {
27+
foo: 'foo',
28+
bar: 'bar',
29+
car: 'car'
30+
}
31+
}));
32+
""");
33+
}));
34+
35+
add(new Button("Click me too", e -> {
36+
// This is in theory bit more efficient for the server
37+
// as it does not need to deserialize-serialize (with GWT library)
38+
// and then desirialize with Jackson, but only once with Jackson
39+
getElement().executeJs("""
40+
this.dispatchEvent(new CustomEvent('foo-bar', {
41+
detail: JSON.stringify({
42+
foo: 'foo',
43+
bar: 'bar',
44+
car: 'car'
45+
})
46+
}));
47+
""");
48+
}));
49+
50+
}
51+
}

0 commit comments

Comments
 (0)