Getting Started
Example project
Goal
The goal is to create a simple user interface for reporting errors. The report should have a description and a type. The following types should be available:
-
Bug
-
Improvement
-
Question
The report can only be submitted if a description has been entered and a type was selected.
Persisting the report is not part of this tutorial. |
Prerequisites
To start this project, you need
-
Java 17
-
your favorite Java IDE
-
Maven
-
a modern browser
Follow the steps described in project setup to create a new linkki project.
Step 1: Domain Model
First, we create a model to describe the domain. The model consists of two classes, Report
and ReportType
. These classes do not receive any UI specific annotations.
public class Report {
private Integer id;
private String description;
private ReportType type;
// getters and setters
}
public enum ReportType {
BUG,
IMPROVEMENT,
QUESTION;
public String getName() {
String name = name();
return name.substring(0, 1) + name.substring(1).toLowerCase();
}
}
ReportType implements the method getName() . This method is called by linkki to display the 'caption' for the enum values.
|
Step 2: PresentationModelObject (PMO)
Our UI should show a text area to enter a description. For the selection of the report type, a combo box with the enum constants of the ReportType
should be displayed. To submit the report, we also require a Send
button. This button should only be active if a description has been entered and a type was selected.
Starting off, we first create a new class in the package org.linkki.samples.gettingstarted.pmo
, naming it ReportSectionPmo
. This class should be annotated with @UISection
.
In addition, the class needs an instance variable to store the Report
, which must be passed to the constructor.
@UISection
public class ReportSectionPmo {
private final Report report;
public ReportSectionPmo(Report report) {
this.report = requireNonNull(report, "report must not be null");
}
}
...
For the model binding to work, a getter method for the report must be created and it must be annotated with @ModelObject
.
@ModelObject
public Report getReport() {
return report;
}
Now we define the text area and the combo box. Each of these UI elements needs a method, annotated with @UITextArea
and @UIComboBox
respectively. The UI anontations must define the properties position
and label
, as well as modelAttribute
which indicates which model property this field represents. These methods do not take any arguments nor need to return anything as the value will be taken from the domain model directly.
@UITextArea(position = 10,
label = "Description",
modelAttribute = "description",
required = RequiredType.REQUIRED,
height = "8em",
width = "50em")
public void description() {
// Use description from report (model object) directly
}
@UIComboBox(position = 20,
label = "Type",
modelAttribute = "type",
required = RequiredType.REQUIRED,
content = AvailableValuesType.ENUM_VALUES_EXCL_NULL)
public void type() {
// - bind value to the property "type" from report
// - use enum constants from ReportType as available values
}
The annotations must always be added to the methods, not the fields of the class. |
The last step is the definition of the button. This requires a method with no arguments and return value that is annotated with @UIButton
. The content of the method will be invoke upon clicking the button.
As a special feature, the button should be activated or not depending on the values in the model. This is determined via the property enabled = EnabledType.DYNAMIC
in the UI annotation.
By setting EnabledType.DYNAMIC
, linkki searches for a method boolean isSendEnabled()
. It is called automatically during the update of the UI. Its return value determines the activation state of the button.
The method name must conform to the convention is[NameOfThePropertyBelongingToTheAnnotatedMethod]Enabled(). The method must be public and return a boolean value. |
@UIButton(position = 30,
caption = "Send",
icon = VaadinIcon.PAPERPLANE,
showIcon = true,
enabled = EnabledType.DYNAMIC)
public void send() {
report.save();
var notification = new Notification(
new Span(String.format("Report with id %d filed!", report.getId())),
new Span("Thank you for reporting!"));
notification.setPosition(Position.TOP_CENTER);
notification.setDuration(3000);
notification.open();
}
/**
* Enable button only if description and type is present.
*
* @return {@code true} if button is enabled otherwise {@code false}
*/
public boolean isSendEnabled() {
String description = report.getDescription();
return description != null && !description.isEmpty()
&& report.getType() != null;
}
Step 3: Vaadin UI
The UI contains "only" the section for the creation of the report.
The first part is "normal" Vaadin code. The interesting linkki parts start at (2)
. The PMO is passed as parameter to the method VaadinUiCreator#createComponent
, as well as a BindingContext
. At last, the created section
must now be set as content
of the UI.
@Route("") (1)
public class GettingStartedUI extends Div {
private static final long serialVersionUID = 1L;
public GettingStartedUI() {
UI.getCurrent().getPage().setTitle("linkki :: Getting Started");
(2)
Component section = VaadinUiCreator.createComponent(new ReportSectionPmo(new Report()),
new BindingContext("report-context"));
add(section);
}
}
1 | Standard Vaadin code |
2 | linkki specific code |
Starting the Application
The application can be started from the command line via
$> mvn spring-boot:run
and is then reachable at http://localhost:8080/linkki-getting-started.