Browse Source

Updated tutorial to v.8.0.0.beta1 (#8298)

tags/8.0.0.beta2
Alejandro 7 years ago
parent
commit
19427ba7c7
1 changed files with 114 additions and 76 deletions
  1. 114
    76
      documentation/tutorial.adoc

+ 114
- 76
documentation/tutorial.adoc View File

@@ -39,6 +39,8 @@ subnav:
[[framework.tutorial]]
= Vaadin Tutorial

WARNING: Please keep in mind that some of the videos and screenshots in this tutorial were built with Vaadin Framework 7 and Designer 1.0. There are some small differences if you use the latest versions.

This tutorial gives you an overview of how you can use https://vaadin.com/framework[Vaadin Framework] to build single-page web UIs for your Java application.
All you need to start with it is JDK 8 and an https://en.wikipedia.org/wiki/Integrated_development_environment[IDE], such as Eclipse.
While this tutorial is written for Eclipse users, you can use your IDE of choice.
@@ -148,9 +150,7 @@ Creating your next Maven-based Vaadin project will be much faster.
Right click on the newly created project and choose "Run as > Maven Install".
This initiates a full build of your application and finally creates a https://en.wikipedia.org/wiki/WAR_(file_format)[WAR] file into the [filename]#target# directory.
You can deploy the WAR file to your application server.
The first build will take a while, as Maven might again need to download some new modules.
Also, the project uses add-ons and contains a project specific theme.
Compiling them takes a while.
The first build might take a while, as Maven might again need to download some new modules.

TIP: For the Maven compilation to work you need a JDK to be configured in your
Eclipse in "Window > Preferences > Java > Installed JREs > Add...".
@@ -245,11 +245,15 @@ video::9-qwPfpSHWc[youtube, width="640", height="400"]
[[framework.tutorial.backend]]
== Adding a demo "backend"

TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/v8-step2.zip[Download the project] for this step, extract the zip file and choose "Import... > Maven > Existing Maven project".

Before getting more into real Vaadin development, let us introduce some domain objects and a "fake backend".
In a real-world application, you will most likely have something similar, implemented with, for example, JPA and EJB or a Spring-based service.

The following video covers steps 3 and 4 (<<framework.tutorial.grid>>) of this tutorial:

WARNING: This video is built with Vaadin Framework 7. There are some small differences if you use the latest version.

video::0W0frepDKWI[youtube, width="640", height="400"]

Copy the following three classes from github to your project.
@@ -272,7 +276,7 @@ The actual implementation of these classes is not relevant for this tutorial, bu
[[framework.tutorial.grid]]
== Listing entities in a Grid

TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/step3.zip[Download the project] for this step, extract the zip file and choose "Import... > Maven > Existing Maven project".
TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/v8-step3.zip[Download the project] for this step, extract the zip file and choose "Import... > Maven > Existing Maven project".

Often when you start building a UI for a data-centric application, the first
thing you want to do is to list your data from your back-end.
@@ -288,7 +292,7 @@ Also, let us get a reference to the [classname]#CustomerService#.
public class MyUI extends UI {
// Add the next two lines:
private CustomerService service = CustomerService.getInstance();
private Grid grid = new Grid();
private Grid<Customer> grid = new Grid<>();

// The rest is already there...
@Override
@@ -319,9 +323,8 @@ protected void init(VaadinRequest vaadinRequest) {

// fetch list of Customers from service and assign it to Grid
List<Customer> customers = service.findAll();
grid.setContainerDataSource(new BeanItemContainer<>(Customer.class, customers));
grid.setItems(customers);

layout.setMargin(true);
setContent(layout);
}
----
@@ -340,18 +343,19 @@ Macs). The extracted method call looks like this:
----
public void updateList() {
List<Customer> customers = service.findAll();
grid.setContainerDataSource(new BeanItemContainer<>(Customer.class, customers));
grid.setItems(customers);
}
----

If you try the application now, you'll see that quite many properties of the
customers are shown in the grid. To limit the visible properties, configure
the Grid using the _setColumns_ method to only show "firstName", "lastName" and
If you try the application now, you'll see an empty Grid with no columns. To add columns, configure
the Grid using the _addColumn_ method to show the "firstName", "lastName" and
"email" properties.

[source,java]
----
grid.setColumns("firstName", "lastName", "email");
grid.addColumn(Customer::getFirstName).setCaption("First Name");
grid.addColumn(Customer::getLastName).setCaption("Last Name");
grid.addColumn(Customer::getEmail).setCaption("Email");
----

At this point the body of the MyUI class should look like this (servlet declaration
@@ -366,20 +370,21 @@ private Grid grid = new Grid();
protected void init(VaadinRequest vaadinRequest) {
final VerticalLayout layout = new VerticalLayout();

grid.setColumns("firstName", "lastName", "email");
grid.addColumn(Customer::getFirstName).setCaption("First Name");
grid.addColumn(Customer::getLastName).setCaption("Last Name");
grid.addColumn(Customer::getEmail).setCaption("Email");
// add Grid to the layout
layout.addComponent(grid);

updateList();

layout.setMargin(true);
setContent(layout);
}

public void updateList() {
// fetch list of Customers from service and assign it to Grid
List<Customer> customers = service.findAll();
grid.setContainerDataSource(new BeanItemContainer<>(Customer.class, customers));
grid.setItems(customers);
}
----

@@ -389,7 +394,7 @@ You can do this at any point during the rest of the tutorial as well.
[[framework.tutorial.filtering]]
== Creating live filtering for entities

TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/step4.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].
TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/v8-step4.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].

A search functionality is expected in every modern application and it is
also a nice Vaadin development exercise. Let's add a filtering functionality to
@@ -397,6 +402,8 @@ the Customer listing we created in the previous step.

The following video shows how to do this step of the tutorial:

WARNING: This video is built with Vaadin Framework 7. There are some small differences if you use the latest version.

video::fAeC_mZH_7w[youtube, width="640", height="400"]

We'll start by introducing a [classname]#TextField# component as a field to our [classname]#UI# class:
@@ -413,27 +420,25 @@ object.

[source,java]
----
filterText.setInputPrompt("filter by name...");
filterText.addTextChangeListener(e -> {
grid.setContainerDataSource(new BeanItemContainer<>(Customer.class,
service.findAll(e.getText())));
});
filterText.setPlaceholder("filter by name...");
filterText.addValueChangeListener(e -> updateList());
filterText.setValueChangeMode(ValueChangeMode.LAZY);
----

TIP: To keep your code more readable, you can use autoformat after you write or
copy paste code snippets. The default keyboard shortcut in Eclipse is
kbd:[Ctrl+Shift+F] or kbd:[Cmd+Shift+F]

The text change listener is another listener (in addition to the more commonly
used ValueChangeListener) you can use with text fields in Vaadin. It is fired
lazily while the user is typing, but only when there is a small pause in the
typing. This makes it perfect for this kind of automatic filtering. When the
user has changed the text, we'll just update the listing like in the updateList
method, but use the current text as a filter for entries.
As its name implies, the value change listener allows you to react to changes in
the value contained in the text field. It is configured so that the event is fired
lazily while the user is typing, when there is a small pause in the typing.
This makes it perfect for this kind of automatic filtering. When the
user has changed the text, we'll just update the listing calling the _updateList_
method.

To keep the _updateList_ method functional, it should also take into
consideration the possible value in the filterText field. Change the line for
fetching the customers into this:
To keep the _updateList_ method functional, it should take into consideration
the possible value in the filterText field. Change the line for fetching the
customers into this:

[source,java]
----
@@ -444,31 +449,27 @@ Before adding the text field to the UI, let's improve the usability a bit
and make a short exercise to compose better components from lower level UI
components. The search field can naturally be cleared with the keyboard, but let's
add a clear button next to the text field. Start by adding the following lines
to the init method, for example right after your filterText configuration:
to the init method, for example right after your _filterText_ configuration:

[source,java]
----
Button clearFilterTextBtn = new Button(FontAwesome.TIMES);
clearFilterTextBtn.setDescription("Clear the current filter");
clearFilterTextBtn.addClickListener(e -> {
filterText.clear();
updateList();
});
clearFilterTextBtn.addClickListener(e -> filterText.clear());
----

Vaadin contains a set of built in icons, from which we use the "X" icon,
_FontAwesome.TIMES_, here, which most users will recognise as a functionality to clear
the value. If we set the description to a component, it will be shown as a
tooltip for those users who hover the cursor over the button and wonder what to
do with it. In the click listener, we simply clear the text from the field and
refresh the content of the listing.
do with it. In the click listener, we simply clear the text from the field.

Vaadin contains lots of different kinds of layouts. The simplest way to align
the text field and the button next to each other would be to use a
HorizontalLayout. An alternative way we use here is using a CssLayout, which is
a lightweight layout that is easy to customize with css. Even if you wouldn't
want to play with CSS yourself, you can often use one of the existing style
rules in the default _Valo_ theme. The following snippet will create a nice
rules in the default https://demo.vaadin.com/valo-theme[_Valo_] theme. The following snippet will create a nice
compact "composition" of both the TextField and the clear button. Add these
lines to the init method right after you configured the _clearFilterTextBtn_:

@@ -479,7 +480,7 @@ filtering.addComponents(filterText, clearFilterTextBtn);
filtering.setStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
----

Finally, *change* the row in the init method that currently adds only the grid,
Finally, *change* the line in the init method that currently adds only the grid,
to add both _filtering_ composition and the _grid_ to the main _layout_ of the
application.

@@ -500,7 +501,7 @@ that. Pick either of them.
[[framework.tutorial.form.designer]]
=== Creating a form using Vaadin Designer

TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/step5.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].
TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/v8-step5.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].

The form to edit Customer objects can be built using several methods of which
the visual composition by drag 'n' drop is the most intuitive. Vaadin
@@ -542,6 +543,8 @@ The following screencast will show you how to produce the
_CustomerFormDesign.html_, a design file we need in this tutorial. Use pause and
slow motion to follow better what is being done in the video. Feel free to get creative!

WARNING: This video is built with Designer 1.0. There are some small differences if you use the latest version.

video::B5dN69NSS78[youtube, width="640", height="400"]

TIP: At any point of the process, you can also switch to the markup mode where
@@ -597,7 +600,6 @@ all of the available space more efficiently. Replace the line
[source,java]
----
HorizontalLayout main = new HorizontalLayout(grid, form);
main.setSpacing(true);
main.setSizeFull();
grid.setSizeFull();
main.setExpandRatio(grid, 1);
@@ -615,7 +617,7 @@ following line to the constructor:

[source,java]
----
status.addItems(CustomerStatus.values());
status.setItems(CustomerStatus.values());
----

Let's also improve the UX a bit. When building the design, we already
@@ -631,8 +633,28 @@ save.setClickShortcut(KeyCode.ENTER);

To finish our form, we need to create a public API that we will use in the next
part from MyUI, to pass in a Customer object that the form should edit. We
will also add some logic to actually save the changes. We'll start by creating a
setter method to the Customer field. Just type _setCus_ in the body of the
will also add some logic to actually save the changes. We'll start by adding a
_BeanBinder_ as a field to the _CustomerForm_ class:

[source,java]
----
private BeanBinder<Customer> beanBinder = new BeanBinder<>(Customer.class);
----

In the constructor of the CustomerForm class add the following line to configure
the BeanBinder:

[source,java]
----
beanBinder.bindInstanceFields(this);
----

This configures the BeanBinder to use all the similary named editor fields in
this form to bind their values with their counterpart in the Customer class.
For example, the _CustomerForm.firstName_ TextField will be bound to the
Customer.firstName property.

Create a setter method for the Customer field. Just type _setCus_ in the body of the
class and hit autocomplete (kbd:[Ctrl+Space]) and Eclipse will create a method
stub for you. Complete it with the following implementation:

@@ -640,7 +662,7 @@ stub for you. Complete it with the following implementation:
----
public void setCustomer(Customer customer) {
this.customer = customer;
BeanFieldGroup.bindFieldsUnbuffered(customer, this);
beanBinder.setBean(customer);

// Show delete button for only customers already in the database
delete.setVisible(customer.isPersisted());
@@ -650,11 +672,9 @@ public void setCustomer(Customer customer) {
----

In addition to saving the reference of the currently edited Customer object, we are
calling the _BeanFieldGroup.bindFieldsUnbuffered_ method. It will initialize all
similarly named editor fields in this form with the values from their
counterpart in the given Customer object. Also, it will automatically update the
values in the domain objects as the corresponding field value changes in the
user interface.
calling the _BeanBinder.setBean_ method. This will initialise all
fields in the form and automatically update the values in the domain objects as
the corresponding field value changes in the user interface.

TIP: If the naming convention based databinding doesn't fit your needs, you
can use
@@ -689,8 +709,8 @@ simple lambda expressions to the constructor will take care of that:

[source,java]
----
save.addClickListener(e->this.save());
delete.addClickListener(e->this.delete());
save.addClickListener(e -> this.save());
delete.addClickListener(e -> this.delete());
----

TIP: For a truly re-usable form component in a real life project, you'd want to
@@ -702,6 +722,8 @@ simplicity.
[[framework.tutorial.form.java]]
=== Creating a form using plain Java

TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/v8-step5.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].

This is an alternative step to the <<Creating a form using Vaadin Designer>>,
where you'll build the form UI programmatically in plain Java. If you already
completed the step using Vaadin Designer, you can proceed to
@@ -709,6 +731,8 @@ completed the step using Vaadin Designer, you can proceed to

The following video shows how to create a form using plain Java:

WARNING: This video is built with Vaadin Framework 7. There are some small differences if you use the latest version.

video::OA6-lSxiXO0[youtube, width="640", height="400"]

Start by creating a new Java class with the name CustomerForm. In Eclipse right
@@ -718,7 +742,7 @@ click _finish_.

In the form, we'll need editor fields for each property in our Customer domain
class. There are different kinds of fields in Vaadin for editing different kinds
of properties. In this example, we'll use a TextField, a PopupDateField and a
of properties. In this example, we'll use a TextField, a DateField and a
NativeSelect. Add the following field declarations and action buttons as Java
fields to the CustomerForm:

@@ -727,8 +751,8 @@ fields to the CustomerForm:
private TextField firstName = new TextField("First name");
private TextField lastName = new TextField("Last name");
private TextField email = new TextField("Email");
private NativeSelect status = new NativeSelect("Status");
private PopupDateField birthdate = new PopupDateField("Birthday");
private NativeSelect<CustomerStatus> status = new NativeSelect<>("Status");
private DateField birthdate = new DateField("Birthday");
private Button save = new Button("Save");
private Button delete = new Button("Delete");
----
@@ -748,7 +772,6 @@ public CustomerForm(MyUI myUI) {

setSizeUndefined();
HorizontalLayout buttons = new HorizontalLayout(save, delete);
buttons.setSpacing(true);
addComponents(firstName, lastName, email, status, birthdate, buttons);
}
----
@@ -773,7 +796,6 @@ all of the available space more efficiently. Replace the line
[source,java]
----
HorizontalLayout main = new HorizontalLayout(grid, form);
main.setSpacing(true);
main.setSizeFull();
grid.setSizeFull();
main.setExpandRatio(grid, 1);
@@ -791,7 +813,7 @@ following line to the constructor:

[source,java]
----
status.addItems(CustomerStatus.values());
status.setItems(CustomerStatus.values());
----

Let's also improve the UX a bit. The most common thing your users will want to
@@ -807,8 +829,28 @@ save.setClickShortcut(KeyCode.ENTER);

To finish our form, we need to create a public API that we will use in the next
part from the MyUI, to pass in a Customer object that the form should edit. We
will also add some logic to actually save the changes. We'll start by creating a
setter method for the Customer field. Just type _setCus_ in the body of the
will also add some logic to actually save the changes. We'll start by adding a
_BeanBinder_ as a field to the _CustomerForm_ class:

[source,java]
----
private BeanBinder<Customer> beanBinder = new BeanBinder<>(Customer.class);
----

In the constructor of the CustomerForm class add the following line to configure
the BeanBinder:

[source,java]
----
beanBinder.bindInstanceFields(this);
----

This configures the BeanBinder to use all the similary named editor fields in
this form to bind their values with their counterpart in the Customer class.
For example, the _CustomerForm.firstName_ TextField will be bound to the
Customer.firstName property.

Create a setter method for the Customer field. Just type _setCus_ in the body of the
class and hit autocomplete (kbd:[Ctrl+Space]) and Eclipse will create a method
stub for you. Complete it with the following implementation:

@@ -816,7 +858,7 @@ stub for you. Complete it with the following implementation:
----
public void setCustomer(Customer customer) {
this.customer = customer;
BeanFieldGroup.bindFieldsUnbuffered(customer, this);
beanBinder.setBean(customer);

// Show delete button for only customers already in the database
delete.setVisible(customer.isPersisted());
@@ -826,15 +868,13 @@ public void setCustomer(Customer customer) {
----

In addition to saving the reference of the currently edited Customer object, we are
calling _BeanFieldGroup.bindFieldsUnbuffered_ method. It will initialise all
similarly named editor fields in this form with the values from their
counterpart in the given Customer object. Also, it will automatically update the
values in the domain objects as the corresponding field value changes in the
user interface.
calling the _BeanBinder.setBean_ method. This will initialise all
fields in the form and automatically update the values in the domain objects as
the corresponding field value changes in the user interface.

TIP: If the naming convention based databinding doesn't fit your needs, you
can use
https://www.vaadin.com/api/com/vaadin/data/fieldgroup/PropertyId.html[PropertyId]
https://www.vaadin.com/api/com/vaadin/annotations/PropertyId.html[PropertyId]
annotation on fields to explicitly declare the edited property.

We'll also want to ensure the form is visible and that the focus goes to the
@@ -865,8 +905,8 @@ simple lambda expressions to the constructor will take care of that:

[source,java]
----
save.addClickListener(e->this.save());
delete.addClickListener(e->this.delete());
save.addClickListener(e -> this.save());
delete.addClickListener(e -> this.delete());
----

TIP: For a truly re-usable form component in a real life project, you'd want to
@@ -878,7 +918,7 @@ simplicity.
[[framework.tutorial.form-connection]]
== Connecting the form to the application

TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/step6.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].
TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/v8-step6.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].

In this part, we'll use the CustomerForm class, which we created in the
previous step, from the MyUI class. We will use it for both editing the existing
@@ -902,12 +942,11 @@ the end of the _init_ method:

[source,java]
----
grid.addSelectionListener(event -> {
if (event.getSelected().isEmpty()) {
grid.asSingleSelect().addValueChangeListener(event -> {
if (event.getValue() == null) {
form.setVisible(false);
} else {
Customer customer = (Customer) event.getSelected().iterator().next();
form.setCustomer(customer);
form.setCustomer(event.getValue());
}
});
----
@@ -927,7 +966,7 @@ right after where you introduced the _filtering_ composition:
----
Button addCustomerBtn = new Button("Add new customer");
addCustomerBtn.addClickListener(e -> {
grid.select(null);
grid.asSingleSelect().clear();
form.setCustomer(new Customer());
});
----
@@ -942,7 +981,6 @@ this after the previously created _addCustomerBtn_:
[source,java]
----
HorizontalLayout toolbar = new HorizontalLayout(filtering, addCustomerBtn);
toolbar.setSpacing(true);
----

And, again, *replace* the line that populates your main layout to add the

Loading…
Cancel
Save