Custom Flow Components in Hilla
Custom Flow components can be embedded in a Hilla view by implementing a WebComponentExporter
and using it in the view. A WebComponentExporter
can target any Flow Component.
Below is an example for a component that follows this:
public class CustomComponent extends Div {
public CustomComponent(@Autowired GreetService service) {
Button button = new Button("Say hello", e -> {
Notification.show("Hello!");
});
add(button);
}
}
This would then be embedded into a WebComponent
like so:
public class MyFlowComponentExporter
extends WebComponentExporter<CustomComponent> {
public static final String TAG = "my-flow-component";
public MyFlowComponentExporter() {
super(TAG);
}
@Override
protected void configureInstance(WebComponent<CustomComponent> webComponent,
CustomComponent component) {
}
}
For more information, see Creating an Embedded Vaadin Application.
Note
|
The WebComponentExporter needs to have a public no-argument constructor. Otherwise, it won’t be instantiated or generated.
|
To add the exported WebComponent
to a Hilla view, import reactElement
from Flow and create a React.DOMElement
for the WebComponent
TAG
. Then use the element inside the view layout like this:
import { VerticalLayout } from "@vaadin/react-components/VerticalLayout";
import { reactElement } from "Frontend/generated/flow/Flow";
function MyFlowComponent() {
return reactElement("my-flow-component");
}
export default function HillaView() {
return (
<>
<VerticalLayout className={'centered-content'}>
<h3>Hilla View</h3>
<MyFlowComponent/>
</VerticalLayout>
</>
);
}
Using Attributes
Adding attributes for the element can be done by giving a Properties
object with string
value pairs to the reactElement
. The Properties
is defined as [key: string]: string;
.
This can be used when the WebComponent
exposes properties to the client.
import { VerticalLayout } from "@vaadin/react-components/VerticalLayout";
import { reactElement } from "Frontend/generated/flow/Flow";
import React from "react";
function MyFlowComponent() {
// Create element with property hellomsg
return reactElement("my-flow-component", {
hellomsg: 'Hi from the client!'
});
}
export default function HillaView() {
return (
<>
<VerticalLayout className={'centered-content'}>
<h3>Hilla View</h3>
<MyFlowComponent/>
</VerticalLayout>
</>
);
}
The properties can also be linked to the element attributes using a custom properties type:
import { VerticalLayout } from "@vaadin/react-components/VerticalLayout";
import { reactElement } from "Frontend/generated/flow/Flow";
import React from "react";
type MyProperties = {
hellomsg: string
}
function MyFlowComponent(props: MyProperties) {
// Create element with property hellomsg
return reactElement("my-flow-component", {
hellomsg: props.hellomsg
});
}
export default function HillaView() {
return (
<>
<VerticalLayout className={'centered-content'}>
<h3>Hilla View</h3>
<MyFlowComponent hellomsg={'Hi from the client!'}/>
</VerticalLayout>
</>
);
}
In this way, changing the attribute will also update the WebComponent
property value.
The corresponding server-side code for the attribute component is made as the following example shows:
public class MyFlowComponentExporter
extends WebComponentExporter<CustomComponent> {
public static final String TAG = "my-flow-component";
public MyFlowComponentExporter() {
super(TAG);
addProperty("hellomsg", "Hello!")
.onChange(CustomComponent::setHelloMessage);
}
@Override
protected void configureInstance(WebComponent<CustomComponent> webComponent,
CustomComponent component) {
}
}
public class CustomComponent extends Div {
String helloMessage;
public CustomComponent(@Autowired GreetService service) {
Button button = new Button("Say hello", e -> {
Notification.show(helloMessage);
});
add(button);
}
public void setHelloMessage(String helloMessage) {
this.helloMessage = helloMessage;
}
}
Onload Event for WebComponent
Loading the WebComponent
script can take some time, depending on the network. Therefore, it might be prudent to show a loading indicator so the user knows to wait.
It’s possible to listen to the onload
event for the WebComponent
script so that the loading element can be removed when the script is finished loading.
The reactElement
accepts an onload callback function as the third parameter. An onerror callback can be set as the fourth parameter. However, if it’s not given, there will be an error logged into the console with the script tag to show which WebComponent
script failed to load.
import { VerticalLayout } from "@vaadin/react-components/VerticalLayout";
import { reactElement } from "Frontend/generated/flow/Flow";
import React from "react";
type MyProperties = {
hellomsg: string
}
function MyFlowComponent(props: MyProperties) {
// Create element with property hellomsg
return reactElement("my-flow-component",
undefined,
() => document.getElementById("loading")?.remove()
);
}
export default function HillaView() {
return (
<>
<VerticalLayout className={'centered-content'}>
<h3>Hilla View</h3>
<!-- Placeholder element for MyFlowComponent script loading -->
<div id={"loading"}>Loading script...</div>
<MyFlowComponent hellomsg={'Hi from the client!'}/>
</VerticalLayout>
</>
);
}
920dc03d-5eb4-4826-8934-4416b58a9a3e