summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Lumme <erik@vaadin.com>2017-09-15 13:18:47 +0300
committerErik Lumme <erik@vaadin.com>2017-09-15 13:18:47 +0300
commit2c54f81dba19b205e225434b1b93f0cb6f238248 (patch)
tree08070327ead952150e80ef3c0ebb36de420856e0
parent5a8679c8dc667000086d79d586639bcb43af88ad (diff)
downloadvaadin-framework-2c54f81dba19b205e225434b1b93f0cb6f238248.tar.gz
vaadin-framework-2c54f81dba19b205e225434b1b93f0cb6f238248.zip
Migrate CreatingAMasterDetailsViewForEditingPersons
-rw-r--r--documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc382
-rw-r--r--documentation/articles/contents.asciidoc1
-rw-r--r--documentation/articles/img/buttons added.pngbin0 -> 87049 bytes
-rw-r--r--documentation/articles/img/database connected.pngbin0 -> 196481 bytes
-rw-r--r--documentation/articles/img/master detail wireframe.jpgbin0 -> 37394 bytes
-rw-r--r--documentation/articles/img/table and form.pngbin0 -> 81518 bytes
6 files changed, 383 insertions, 0 deletions
diff --git a/documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc b/documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc
new file mode 100644
index 0000000000..7ad2e94967
--- /dev/null
+++ b/documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc
@@ -0,0 +1,382 @@
+[[creating-a-master-details-view-for-editing-persons]]
+Creating a master details view for editing persons
+--------------------------------------------------
+
+[[set-up]]
+Set-up
+~~~~~~
+
+In this tutorial we go through a standard use case where you have a bean
+and a backend ready with create, read, update and delete capabilities on
+that bean. You want to create a view where you can view all the beans
+and edit them. This example is an address book where you edit person
+information. The bean and the backend that we're going to use looks like
+this:
+
+[[person]]
+Person
+^^^^^^
+
+[source,java]
+....
+public class Person {
+ private int id = -1;
+ private String firstName = "";
+ private String lastName = "";
+ private Address address = new Address();
+ private String phoneNumber = "";
+ private String email = "";
+ private Date dateOfBirth = null;
+ private String comments = "";
+....
+
+[[ibackend]]
+IBackend
+^^^^^^^^
+
+[source,java]
+....
+public interface IBackend {
+ public List<Person> getPersons();
+ public void storePerson(Person person);
+ public void deletePerson(Person person);
+}
+....
+
+The view will contain a table, with all the persons in it, and a form
+for editing a single person. Additionally the table will have buttons
+too add or remove persons and the form will have buttons to save and
+discard changes. The UI wireframe looks like this:
+
+image:img/master%20detail%20wireframe.jpg[Master detail UI wireframe]
+
+[[building-the-basic-ui]]
+Building the basic UI
+~~~~~~~~~~~~~~~~~~~~~
+
+We start off with creating a basic UIfor our application
+
+[source,java]
+....
+public class AddressFormsUI extends UI {
+ @Override
+ protected void init(VaadinRequest request) {
+ VerticalLayout mainLayout = new VerticalLayout();
+ mainLayout.setSpacing(true);
+ mainLayout.setMargin(true);
+ mainLayout.addComponent(new Label("Hello Vaadiners!"));
+ setContent(mainLayout);
+ }
+}
+....
+
+The first things that we want to add to it is the table and the form.
+The table should be selectable and immediate so that we're able to pass
+person objects from it to the form. I will create all the fields for our
+person editor by hand to get more flexibility in how the fields will be
+built and laid out. You could also let Vaadin `FieldGroup` take care of
+creating the standard fields with the `buildAndBind` -methods if you don't
+need to customize them.
+
+[source,java]
+....
+package com.example.addressforms;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.TextArea;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+public class AddressFormsUI extends UI {
+
+ private GridLayout form;
+ private Table table;
+
+ @Override
+ protected void init(VaadinRequest request) {
+ VerticalLayout mainLayout = new VerticalLayout();
+ mainLayout.setSpacing(true);
+ mainLayout.setMargin(true);
+
+ mainLayout.addComponent(buildTable());
+ mainLayout.addComponent(buildForm());
+
+ setContent(mainLayout);
+ }
+
+ private Component buildTable() {
+ table = new Table(null);
+ table.setWidth("500px");
+ table.setSelectable(true);
+ table.setImmediate(true);
+ return table;
+ }
+
+ private Component buildForm() {
+ form = new GridLayout(2, 3);
+
+ TextField firstName = new TextField("First name:");
+ TextField lastName = new TextField("Last name:");
+ TextField phoneNumber = new TextField("Phone Number:");
+ TextField email = new TextField("E-mail address:");
+ DateField dateOfBirth = new DateField("Date of birth:");
+ TextArea comments = new TextArea("Comments:");
+
+ form.addComponent(firstName);
+ form.addComponent(lastName);
+ form.addComponent(phoneNumber);
+ form.addComponent(email);
+ form.addComponent(dateOfBirth);
+ form.addComponent(comments);
+ return form;
+ }
+}
+....
+
+image:img/table%20and%20form.png[Address form]
+
+We also want the add, remove, save and discard buttons so let's create
+them as well. I've positioned the add and remove above the table and
+save and discard below the form.
+
+[source,java]
+....
+private GridLayout form;
+private HorizontalLayout tableControls;
+private Table table;
+private HorizontalLayout formControls;
+
+@Override
+protected void init(VaadinRequest request) {
+ VerticalLayout mainLayout = new VerticalLayout();
+ mainLayout.setSpacing(true);
+ mainLayout.setMargin(true);
+
+ mainLayout.addComponent(buildTableControls());
+ mainLayout.addComponent(buildTable());
+ mainLayout.addComponent(buildForm());
+ mainLayout.addComponent(buildFormControls());
+
+ setContent(mainLayout);
+}
+
+...
+
+private Component buildTableControls() {
+ tableControls = new HorizontalLayout();
+ Button add = new Button("Add");
+ Button delete = new Button("Delete");
+ tableControls.addComponent(add);
+ tableControls.addComponent(delete);
+ return tableControls;
+}
+
+private Component buildFormControls() {
+ formControls = new HorizontalLayout();
+ Button save = new Button("Save");
+ Button discard = new Button("Discard");
+ formControls.addComponent(save);
+ formControls.addComponent(discard);
+ return formControls;
+}
+....
+
+The buttons doesn't do anything yet but we have all the components that
+we need in the view now.
+
+image:img/buttons%20added.png[Address form with add, delete, save and discard buttons]
+
+[[connecting-the-backend-to-the-view]]
+Connecting the backend to the view
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The backend reference is store as a field so that all methods have
+access to it.
+
+[source,java]
+....
+...
+private IBackend backend;
+
+@Override
+protected void init(VaadinRequest request) {
+ backend = new Backend();
+ ...
+....
+
+Then we have to build a container for the table. I will do it in a
+separate method from the table building so that it can be rebuilt for
+refreshing the table after the initial rendering. We call this method
+once in the initial rendering as well on every button click that
+modifies the list of persons. A good choice of container in this case is
+the `BeanItemContainer` where we specify to the table which columns we
+want to show, and sort the table based on the name.
+
+[source,java]
+....
+...
+private Component buildTable() {
+ table = new Table(null);
+ table.setSelectable(true);
+ table.setImmediate(true);
+ updateTableData();
+ return table;
+}
+
+...
+
+private void updateTableData() {
+ List<Person> persons = backend.getPersons();
+ BeanItemContainer<Person> container = new BeanItemContainer<Person>(
+ Person.class, persons);
+ table.setContainerDataSource(container);
+
+ table.setVisibleColumns(new String[] { "firstName", "lastName",
+ "phoneNumber", "email", "dateOfBirth" });
+ table.setColumnHeaders(new String[] { "First name", "Last name",
+ "Phone number", "E-mail address", "Date of birth" });
+ table.sort(new Object[] { "firstName", "lastName" }, new boolean[] {
+ true, true });
+}
+...
+....
+
+To get the data from the selected person's data into the fields, and the
+changes back into the bean, we will use a FieldGroup. The `FieldGroup`
+should be defined as class variable and it should bind the fields that
+is initialized in `buildForm()`.
+
+[source,java]
+....
+...
+private FieldGroup fieldGroup = new FieldGroup();
+
+...
+
+private Component buildForm() {
+ form = new GridLayout(2, 3);
+
+ TextField firstName = new TextField("First name:");
+ TextField lastName = new TextField("Last name:");
+ TextField phoneNumber = new TextField("Phone Number:");
+ TextField email = new TextField("E-mail address:");
+ DateField dateOfBirth = new DateField("Date of birth:");
+ TextArea comments = new TextArea("Comments:");
+
+ fieldGroup.bind(firstName, "firstName");
+ fieldGroup.bind(lastName, "lastName");
+ fieldGroup.bind(phoneNumber, "phoneNumber");
+ fieldGroup.bind(email, "email");
+ fieldGroup.bind(dateOfBirth, "dateOfBirth");
+ fieldGroup.bind(comments, "comments");
+
+ form.addComponent(firstName);
+ form.addComponent(lastName);
+ form.addComponent(phoneNumber);
+ form.addComponent(email);
+ form.addComponent(dateOfBirth);
+ form.addComponent(comments);
+ return form;
+}
+....
+
+Additionally the table requires a value change listener and the
+currently selected person in the table has to be passed to the
+`FieldGroup`.
+
+[source,java]
+....
+private Component buildTable() {
+ ...
+ table.addValueChangeListener(new ValueChangeListener() {
+ public void valueChange(ValueChangeEvent event) {
+ editPerson((Person) table.getValue());
+ }
+ });
+ ...
+}
+
+...
+
+private void editPerson(Person person) {
+ if (person == null) {
+ person = new Person();
+ }
+ BeanItem<Person> item = new BeanItem<Person>(person);
+ fieldGroup.setItemDataSource(item);
+}
+....
+
+[[putting-the-buttons-in-use]]
+Putting the buttons in use
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Last thing we have to do is implement all the buttons that we have in
+the application. Add should create a new Person object and give it to
+the form. Delete should tell the backend to remove the selected person
+and update the table. Save should store the changes into the bean and
+the bean into the backend and update the table. Discard should reset the
+form.
+
+[source,java]
+....
+private Component buildTableControls() {
+ tableControls = new HorizontalLayout();
+ Button add = new Button("Add", new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ editPerson(new Person());
+ }
+ });
+ Button delete = new Button("Delete", new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ backend.deletePerson((Person) table.getValue());
+ updateTableData();
+ }
+ });
+ tableControls.addComponent(add);
+ tableControls.addComponent(delete);
+ return tableControls;
+}
+
+private Component buildFormControls() {
+ formControls = new HorizontalLayout();
+ Button save = new Button("Save", new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ try {
+ fieldGroup.commit();
+ backend.storePerson(((BeanItem<Person>) fieldGroup
+ .getItemDataSource()).getBean());
+ updateTableData();
+ editPerson(null);
+ } catch (CommitException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ Button discard = new Button("Discard", new ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ fieldGroup.discard();
+ }
+ });
+ formControls.addComponent(save);
+ formControls.addComponent(discard);
+ return formControls;
+}
+....
+
+image:img/database%20connected.png[Form with database connected]
+
+That's it! Now you have a full working CRUD view with total control over
+the components and layouts. A little theming and layout adjustments and
+it is ready for production.
+
+You might have noticed that the person bean contains a reference to
+another bean, a address, which is not editable here. The tutorial
+link:CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc[Creating a custom field for editing the address of a person] goes
+through on how to edit beans within beans with a `CustomField`, which can
+be used directly as a field for the `FieldGroup`.
diff --git a/documentation/articles/contents.asciidoc b/documentation/articles/contents.asciidoc
index bb05866fd6..f95b86bfdc 100644
--- a/documentation/articles/contents.asciidoc
+++ b/documentation/articles/contents.asciidoc
@@ -28,3 +28,4 @@
- link:ConfiguringGridColumnWidths.asciidoc[Configuring Grid column widths]
- link:Vaadin7HierarchicalContainerAndTreeComponentExampleWithLiferayOrganizationService.asciidoc[Vaadin 7 hierarchical container and TreeComponent example with Liferay OrganizationService]
- link:CreatingACustomFieldForEditingTheAddressOfAPerson.asciidoc[Creating a CustomField for editing the address of a person]
+- link:CreatingAMasterDetailsViewForEditingPersons.asciidoc[Creating a master details view for editing persons]
diff --git a/documentation/articles/img/buttons added.png b/documentation/articles/img/buttons added.png
new file mode 100644
index 0000000000..26ea5852f9
--- /dev/null
+++ b/documentation/articles/img/buttons added.png
Binary files differ
diff --git a/documentation/articles/img/database connected.png b/documentation/articles/img/database connected.png
new file mode 100644
index 0000000000..80c3588224
--- /dev/null
+++ b/documentation/articles/img/database connected.png
Binary files differ
diff --git a/documentation/articles/img/master detail wireframe.jpg b/documentation/articles/img/master detail wireframe.jpg
new file mode 100644
index 0000000000..4745b4831f
--- /dev/null
+++ b/documentation/articles/img/master detail wireframe.jpg
Binary files differ
diff --git a/documentation/articles/img/table and form.png b/documentation/articles/img/table and form.png
new file mode 100644
index 0000000000..d454da1fd9
--- /dev/null
+++ b/documentation/articles/img/table and form.png
Binary files differ