Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 233 additions & 0 deletions articles/getting-started/tutorial/edit-details.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
---
title: Edit Data
page-title: Add a Form to Edit Products | Vaadin Tutorial
description: 🚧 Work in progress, check back later.
meta-description:
order: 25
---

= Create an Edit Form

In the previous step, you added sorting and filtering to the product catalog view. In this step, you'll add a form to edit products.

.Different Views for Different Use Cases
[NOTE]
If you check the `schema.sql` file, you'll find that the `PRODUCTS` table has more columns than what is currently shown in the grid. This is quite common in applications: the grid shows only a subset of the data, and a form is used to view and edit all the details.

// TODO The form does not yet contain all the columns in the database because it would grow too big for this tutorial. Should the remaining columns be removed from the database schema?

// TODO This becomes too big! Should focus on editing before adding. Adding can be moved to a separate page.

== Create a Form

In Vaadin applications, you often use the same form for adding and editing data. However, the logic for adding and editing is typically different. Therefore, it's a good idea to implement the form as a separate component.

Start by creating a new class `ProductForm` in the `com.example.product` package. The form will use the `FormLayout` to arrange the fields in a responsive grid. You could have `ProductForm` extend `FormLayout` directly, but this would expose all the layout methods to the users of the form. For better encapsulation, extend `Composite<FormLayout>` instead:

Check warning on line 25 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Will] Avoid using 'will'. Raw Output: {"message": "[Vaadin.Will] Avoid using 'will'.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 25, "column": 92}}}, "severity": "WARNING"}

.ProductForm.java
[source,java]
----
package com.example.product;

import com.vaadin.flow.component.Composite;
import com.vaadin.flow.component.formlayout.FormLayout;

class ProductForm extends Composite<FormLayout> { // <1>

ProductForm() {
// The form implementation will go here
}
}
----
<1> `Composite` effectively turns the `ProductForm` into a `FormLayout` while keeping the layout methods hidden.


== Add Fields to the Form

Next, add fields to the form for all the product attributes you want to edit:

* Use <</components/text-field#,Text Field>> and <</components/text-area#,Text Area>> for text attributes.
* Use <</components/date-picker#,Date Picker>> for date attributes.
* Use <</components/number-field#bigdecimal-field,BigDecimal Field>> for decimal attributes like price and discount.

As for the product catalog view, it is a good idea to create and layout the UI components in separate sections of the constructor.

Here's the `ProductForm` class with some fields:

.ProductForm.java
[source,java]
----
package com.example.product;

import com.vaadin.flow.component.Composite;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.textfield.BigDecimalField;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.component.textfield.TextField;

class ProductForm extends Composite<FormLayout> {

ProductForm() {
// Create components
var nameField = new TextField("Name");
var descriptionField = new TextArea("Description");
var categoryField = new TextField("Category");
var brandField = new TextField("Brand");
var skuField = new TextField("SKU");
var releaseDateField = new DatePicker("Release Date");
var priceField = new BigDecimalField("Price");
var discountField = new BigDecimalField("Discount");

// Layout form
var layout = getContent(); // <1>
layout.add(nameField);
layout.add(descriptionField);
layout.add(categoryField);
layout.add(brandField);
layout.add(skuField);
layout.add(releaseDateField);
layout.add(priceField);
layout.add(discountField);
}
}
----
<1> `getContent()` returns the underlying `FormLayout` instance.


== Show the Form in a Dialog

Whenever you build a user interface in Vaadin, you'll want to see the changes right away. To do that, you have to add the form to a view.

.AddProductDialog.java
[source,java]
----
package com.example.product;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dialog.Dialog;

class AddProductDialog extends Dialog {

AddProductDialog() {
// Create components
var form = new ProductForm();
var saveButton = new Button("Save");
saveButton.addThemeName("primary");

var cancelButton = new Button("Cancel");

// Configure dialog
setHeaderTitle("Add Product");
add(form);
getFooter().add(cancelButton, saveButton);
}
}
----

[source,java]
----
var addProductButton = new Button("Add Product", e -> new AddProductDialog().open());
----


[source,java]
----
var toolbar = new HorizontalLayout();
toolbar.setWidthFull();
toolbar.addToStart(searchField);
toolbar.addToEnd(addProductButton);
----

The complete `ProductCatalogView` class now looks like this:

.ProductCatalogView.java
[source,java]
----
package com.example.product;

// tag::snippet[]
import com.vaadin.flow.component.button.Button;
// end::snippet[]
import com.vaadin.flow.component.grid.ColumnTextAlign;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.icon.VaadinIcon;
// tag::snippet[]
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
// end::snippet[]
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.value.ValueChangeMode;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;

@Route("")
@PageTitle("Product Catalog")
class ProductCatalogView extends VerticalLayout {

ProductCatalogView(ProductCatalogItemRepository repository) {
// Create components
var searchField = new TextField();
searchField.setPlaceholder("Search");
searchField.setPrefixComponent(VaadinIcon.SEARCH.create());
searchField.setValueChangeMode(ValueChangeMode.LAZY);

// tag::snippet[]
var addProductButton = new Button("Add Product",
e -> new AddProductDialog().open());
// end::snippet[]

var grid = new Grid<ProductCatalogItem>();
grid.addColumn(ProductCatalogItem::name).setHeader("Name")
.setSortProperty(ProductCatalogItem.SORT_PROPERTY_NAME);
grid.addColumn(ProductCatalogItem::price).setHeader("Price")
.setTextAlign(ColumnTextAlign.END)
.setSortProperty(ProductCatalogItem.SORT_PROPERTY_PRICE);
grid.addColumn(ProductCatalogItem::description).setHeader("Description")
.setSortProperty(ProductCatalogItem.SORT_PROPERTY_DESCRIPTION);
grid.addColumn(ProductCatalogItem::category).setHeader("Category")
.setSortProperty(ProductCatalogItem.SORT_PROPERTY_CATEGORY);
grid.addColumn(ProductCatalogItem::brand).setHeader("Brand")
.setSortProperty(ProductCatalogItem.SORT_PROPERTY_BRAND);
grid.setItemsPageable(pageable -> repository
.findByNameContainingIgnoreCase(searchField.getValue(), pageable)
.getContent()
);

searchField.addValueChangeListener(e ->
grid.getDataProvider().refreshAll());

// Layout view
setSizeFull();
grid.setSizeFull();
// tag::snippet[]
var toolbar = new HorizontalLayout();
toolbar.setWidthFull();
toolbar.addToStart(searchField);
toolbar.addToEnd(addProductButton);
add(toolbar);
// end::snippet[]
add(grid);
}
}
----

== Tweak the Form Layout

TODO

Check failure on line 217 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Terms] Use '[tT]odos?' instead of 'TODO'. Raw Output: {"message": "[Vale.Terms] Use '[tT]odos?' instead of 'TODO'.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 217, "column": 1}}}, "severity": "ERROR"}

Check warning on line 217 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Abbr] 'TODO' has no definition. Raw Output: {"message": "[Vaadin.Abbr] 'TODO' has no definition.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 217, "column": 1}}}, "severity": "WARNING"}

== Create a Form Data Object

TODO

Check warning on line 221 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Abbr] 'TODO' has no definition. Raw Output: {"message": "[Vaadin.Abbr] 'TODO' has no definition.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 221, "column": 1}}}, "severity": "WARNING"}

Check failure on line 221 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Terms] Use '[tT]odos?' instead of 'TODO'. Raw Output: {"message": "[Vale.Terms] Use '[tT]odos?' instead of 'TODO'.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 221, "column": 1}}}, "severity": "ERROR"}

== Add a Binder

TODO

Check warning on line 225 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Abbr] 'TODO' has no definition. Raw Output: {"message": "[Vaadin.Abbr] 'TODO' has no definition.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 225, "column": 1}}}, "severity": "WARNING"}

Check failure on line 225 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Terms] Use '[tT]odos?' instead of 'TODO'. Raw Output: {"message": "[Vale.Terms] Use '[tT]odos?' instead of 'TODO'.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 225, "column": 1}}}, "severity": "ERROR"}

== Add Repository Methods for Saving

TODO

Check failure on line 229 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Terms] Use '[tT]odos?' instead of 'TODO'. Raw Output: {"message": "[Vale.Terms] Use '[tT]odos?' instead of 'TODO'.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 229, "column": 1}}}, "severity": "ERROR"}

Check warning on line 229 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Abbr] 'TODO' has no definition. Raw Output: {"message": "[Vaadin.Abbr] 'TODO' has no definition.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 229, "column": 1}}}, "severity": "WARNING"}

== Implement Save and Cancel

TODO

Check warning on line 233 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Abbr] 'TODO' has no definition. Raw Output: {"message": "[Vaadin.Abbr] 'TODO' has no definition.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 233, "column": 1}}}, "severity": "WARNING"}

Check failure on line 233 in articles/getting-started/tutorial/edit-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Terms] Use '[tT]odos?' instead of 'TODO'. Raw Output: {"message": "[Vale.Terms] Use '[tT]odos?' instead of 'TODO'.", "location": {"path": "articles/getting-started/tutorial/edit-details.adoc", "range": {"start": {"line": 233, "column": 1}}}, "severity": "ERROR"}
13 changes: 12 additions & 1 deletion articles/getting-started/tutorial/list-data.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ In production applications, you should never perform unbounded queries that can
.ProductCatalogView.java
[source,java]
----
package com.example.product;

import com.vaadin.flow.component.grid.ColumnTextAlign;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;

@Route("")
@PageTitle("Product Catalog")
class ProductCatalogView extends VerticalLayout {
Expand All @@ -173,7 +181,10 @@ class ProductCatalogView extends VerticalLayout {
grid.addColumn(ProductCatalogItem::category).setHeader("Category");
grid.addColumn(ProductCatalogItem::brand).setHeader("Brand");
// tag::snippet[]
grid.setItemsPageable(pageable -> repository.findAll(pageable).getContent()); // <2>
grid.setItemsPageable(pageable -> repository
.findAll(pageable)
.getContent()
); // <2>
// end::snippet[]

// Layout view
Expand Down
11 changes: 0 additions & 11 deletions articles/getting-started/tutorial/modify-data.adoc

This file was deleted.

4 changes: 2 additions & 2 deletions articles/getting-started/tutorial/setup.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ To get started quickly, you'll use an existing H2 database file that contains th
The `schema.sql` file contains the database schema, and the `data.sql` file contains sample data. Spring Boot automatically executes these files when the application starts, setting up the database for you.


== Start the Application
== Run the Application

To make sure everything is set up correctly, start the application <<../dev-environment/run#,from your IDE>>. Since the application doesn't have any views yet, navigating to http://localhost:8080 should show a "No views found" page. You should not see any errors in the application console output.
To make sure everything is set up correctly, run the application <<../dev-environment/run#,from your IDE>>. Since the application doesn't have any views yet, navigating to http://localhost:8080 should show a "No views found" page. You should not see any errors in the application console output.


== Next Steps
Expand Down
11 changes: 11 additions & 0 deletions articles/getting-started/tutorial/show-details.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: Show Details
page-title: Add a Form to View Product Details | Vaadin Tutorial
description: 🚧 Work in progress, check back later.
meta-description:
order: 20
---

= Create a Product Details Form

TODO

Check warning on line 11 in articles/getting-started/tutorial/show-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Abbr] 'TODO' has no definition. Raw Output: {"message": "[Vaadin.Abbr] 'TODO' has no definition.", "location": {"path": "articles/getting-started/tutorial/show-details.adoc", "range": {"start": {"line": 11, "column": 1}}}, "severity": "WARNING"}

Check failure on line 11 in articles/getting-started/tutorial/show-details.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Terms] Use '[tT]odos?' instead of 'TODO'. Raw Output: {"message": "[Vale.Terms] Use '[tT]odos?' instead of 'TODO'.", "location": {"path": "articles/getting-started/tutorial/show-details.adoc", "range": {"start": {"line": 11, "column": 1}}}, "severity": "ERROR"}
Loading
Loading