Skip to content

Commit 9ed4ee5

Browse files
committed
Added enhancments
1 parent 5804d80 commit 9ed4ee5

File tree

2 files changed

+130
-33
lines changed

2 files changed

+130
-33
lines changed

src/main/java/org/vaadin/addons/velocitycomponent/VElement.java

+50-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.fasterxml.jackson.core.JsonProcessingException;
44
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.vaadin.flow.component.UI;
56
import com.vaadin.flow.dom.Element;
67
import com.vaadin.flow.function.SerializableConsumer;
78
import com.vaadin.flow.shared.Registration;
@@ -21,6 +22,10 @@ private VElement(Element element) {
2122
this.element = element;
2223
}
2324

25+
public static VElement body() {
26+
return new VElement(UI.getCurrent().getElement());
27+
}
28+
2429
public static VElement of(Element element) {
2530
return new VElement(element);
2631
}
@@ -43,11 +48,11 @@ public <T> Registration on(Class<T> eventType, SerializableConsumer<T> listener)
4348
if(simpleName.endsWith("Event")) {
4449
simpleName = simpleName.substring(0, simpleName.length() - 5);
4550
}
46-
String kebabCased = stream(StringUtils.splitByCharacterTypeCamelCase(simpleName))
51+
String eventName = stream(StringUtils.splitByCharacterTypeCamelCase(simpleName))
4752
.map(s -> s.toLowerCase())
4853
.reduce((a, b) -> a + "-" + b).get();
4954

50-
return element.addEventListener(kebabCased, event -> {
55+
return element.addEventListener(eventName, event -> {
5156
JsonValue jsonValue = event.getEventData().get("event.detail");
5257
T value;
5358
if(jsonValue.getType() == JsonType.OBJECT) {
@@ -66,4 +71,47 @@ public <T> Registration on(Class<T> eventType, SerializableConsumer<T> listener)
6671
listener.accept(value);
6772
}).addEventData("event.detail");
6873
}
74+
75+
/**
76+
* Listen to a custom client side event and receive the payload in "event.detail".
77+
* If the event type/payload is not String, Integer, Double or Boolean, it is expected to be a JSON
78+
* and deserialized to the event type using Jackson ObjectMapper.
79+
*
80+
* On the client side, the event should be dispatched with a CustomEvent with the detail property.
81+
*
82+
* @param eventName the name of the event
83+
* @param eventType the DTO of the "event.detail"
84+
* @param listener the listener to be called when the event is fired
85+
* @return a registration that can be used to remove the listener
86+
* @param <T> the type of the event
87+
*/
88+
public <T> Registration on(String eventName, Class<T> eventType, SerializableConsumer<T> listener) {
89+
return element.addEventListener(eventName, event -> {
90+
JsonValue jsonValue = event.getEventData().get("event.detail");
91+
T value;
92+
if(eventType == String.class) {
93+
value = (T) jsonValue.asString();
94+
} else if(eventType == Integer.class) {
95+
value = (T) Integer.valueOf((int) jsonValue.asNumber());
96+
} else if(eventType == Double.class) {
97+
value = (T) Double.valueOf(jsonValue.asNumber());
98+
} else if(eventType == Boolean.class) {
99+
value = (T) Boolean.valueOf(jsonValue.asBoolean());
100+
} else if(jsonValue.getType() == JsonType.OBJECT) {
101+
try {
102+
value = objectMapper.readValue(jsonValue.toJson(), eventType);
103+
} catch (Exception e) {
104+
throw new RuntimeException(e);
105+
}
106+
} else {
107+
try {
108+
value = objectMapper.readValue(jsonValue.asString().toString(), eventType);
109+
} catch (JsonProcessingException e) {
110+
throw new RuntimeException(e);
111+
}
112+
}
113+
listener.accept(value);
114+
}).addEventData("event.detail");
115+
}
116+
69117
}

src/test/java/org/vaadin/addons/usageexample/VElementView.java

+80-31
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,98 @@
33
import com.vaadin.flow.component.button.Button;
44
import com.vaadin.flow.component.html.H1;
55
import com.vaadin.flow.component.html.Paragraph;
6+
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
67
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
78
import com.vaadin.flow.router.Route;
89
import org.vaadin.addons.velocitycomponent.VElement;
910

1011
@Route
1112
public class VElementView extends VerticalLayout {
1213

13-
public record FooBar(String foo, String bar, String car) {}
14+
public VElementView() {
15+
add(new H1("Example to listen DOM events easily!"));
1416

15-
public VElementView() {
16-
add(new H1("Example to listen DOM events easily!"));
17+
VElement.of(getElement()).on(FooBar.class, event -> {
18+
String bar = event.bar();
19+
add(new Paragraph("Received foo-bar event with detail: " + event));
20+
});
21+
// Event name can also be specified explicitly
22+
VElement.of(getElement()).on("foo-car", FooBar.class, event -> {
23+
String bar = event.bar();
24+
add(new Paragraph("Received foo-car event with detail: " + event));
25+
});
26+
VElement.of(getElement()).on("string-msg", String.class, event -> {
27+
add(new Paragraph("Received string-msg event with detail: " + event));
28+
});
29+
VElement.of(getElement()).on("boolean-msg", String.class, event -> {
30+
add(new Paragraph("Received boolean-msg event with detail: " + event));
31+
});
32+
VElement.of(getElement()).on("int-msg", Integer.class, event -> {
33+
add(new Paragraph("Received int-msg event with detail: " + event));
34+
});
35+
VElement.of(getElement()).on("double-msg", Double.class, event -> {
36+
add(new Paragraph("Received double-msg event with detail: " + event));
37+
});
1738

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 -> {
39+
add(new HorizontalLayout(
40+
new Button("Click me", e -> {
2441
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 -> {
42+
this.dispatchEvent(new CustomEvent('foo-bar', {
43+
detail: {
44+
foo: 'foo',
45+
bar: 'bar',
46+
car: 'car'
47+
}
48+
}));
49+
""");
50+
}),
51+
new Button("Click me too", e -> {
3652
// This is in theory bit more efficient for the server
3753
// as it does not need to deserialize-serialize (with GWT library)
3854
// and then desirialize with Jackson, but only once with Jackson
3955
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-
}
56+
this.dispatchEvent(new CustomEvent('foo-car', {
57+
detail: JSON.stringify({
58+
foo: 'foo',
59+
bar: 'bar',
60+
car: 'car'
61+
})
62+
}));
63+
""");
64+
}),
65+
new Button("Fire string", e -> {
66+
getElement().executeJs("""
67+
this.dispatchEvent(new CustomEvent('string-msg', {
68+
detail: 'foo'
69+
}));
70+
""");
71+
}),
72+
new Button("Fire boolean", e -> {
73+
getElement().executeJs("""
74+
this.dispatchEvent(new CustomEvent('boolean-msg', {
75+
detail: true
76+
}));
77+
""");
78+
}),
79+
new Button("Fire int", e -> {
80+
getElement().executeJs("""
81+
this.dispatchEvent(new CustomEvent('int-msg', {
82+
detail: 1
83+
}));
84+
""");
85+
}),
86+
new Button("Fire double", e -> {
87+
getElement().executeJs("""
88+
this.dispatchEvent(new CustomEvent('double-msg', {
89+
detail: 1.2345
90+
}));
91+
""");
92+
})
93+
));
94+
95+
96+
}
97+
98+
public record FooBar(String foo, String bar, String car) {
99+
}
51100
}

0 commit comments

Comments
 (0)