diff options
author | Erik Lumme <erik@vaadin.com> | 2017-09-15 13:18:47 +0300 |
---|---|---|
committer | Erik Lumme <erik@vaadin.com> | 2017-09-15 13:18:47 +0300 |
commit | 2c54f81dba19b205e225434b1b93f0cb6f238248 (patch) | |
tree | 08070327ead952150e80ef3c0ebb36de420856e0 | |
parent | 5a8679c8dc667000086d79d586639bcb43af88ad (diff) | |
download | vaadin-framework-2c54f81dba19b205e225434b1b93f0cb6f238248.tar.gz vaadin-framework-2c54f81dba19b205e225434b1b93f0cb6f238248.zip |
Migrate CreatingAMasterDetailsViewForEditingPersons
-rw-r--r-- | documentation/articles/CreatingAMasterDetailsViewForEditingPersons.asciidoc | 382 | ||||
-rw-r--r-- | documentation/articles/contents.asciidoc | 1 | ||||
-rw-r--r-- | documentation/articles/img/buttons added.png | bin | 0 -> 87049 bytes | |||
-rw-r--r-- | documentation/articles/img/database connected.png | bin | 0 -> 196481 bytes | |||
-rw-r--r-- | documentation/articles/img/master detail wireframe.jpg | bin | 0 -> 37394 bytes | |||
-rw-r--r-- | documentation/articles/img/table and form.png | bin | 0 -> 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 Binary files differnew file mode 100644 index 0000000000..26ea5852f9 --- /dev/null +++ b/documentation/articles/img/buttons added.png diff --git a/documentation/articles/img/database connected.png b/documentation/articles/img/database connected.png Binary files differnew file mode 100644 index 0000000000..80c3588224 --- /dev/null +++ b/documentation/articles/img/database connected.png diff --git a/documentation/articles/img/master detail wireframe.jpg b/documentation/articles/img/master detail wireframe.jpg Binary files differnew file mode 100644 index 0000000000..4745b4831f --- /dev/null +++ b/documentation/articles/img/master detail wireframe.jpg diff --git a/documentation/articles/img/table and form.png b/documentation/articles/img/table and form.png Binary files differnew file mode 100644 index 0000000000..d454da1fd9 --- /dev/null +++ b/documentation/articles/img/table and form.png |