Like for Create, for the
Update use case also a controller
action method is defined in the BookController
class:
public class BookController { ... public String update( String isbn, String title, int year) { try { Book.update( em, ut, isbn, title, year); } catch ( Exception e) { e.printStackTrace(); } return "update"; } ... }
The Book.update takes care of saving property value
changes for a book object identified by its isbn value as
shown below:
public class Book { ... public static void update( EntityManager em, UserTransaction ut, String isbn, String title, int year) throws Exception { ut.begin(); Book book = em.find( Book.class, isbn); if (title != null && !title.equals( book.title)) { book.setTitle( title); } if (year != book.year) { book.setYear( year); } ut.commit(); } ... }
Now, we create the view where a Book can be selected so
the user can edit the title and year properties,
and then save the changes. The code for this view is stored in the
WebContent/views/books/update.xhtml file which has
the following content:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="..." xmlns:h="..." xmlns:f="..." xmlns:p="...">
<ui:composition template="/WEB-INF/templates/page.xhtml">
<ui:define name="headerTitle">
<h1>Update a book record</h1>
</ui:define>
<ui:define name="main">
<h:form id="updateBookForm">
<div><h:outputLabel for="selectBook" value="Select book: ">
<h:selectOneMenu id="selectBook" value="#{book.isbn}">
<f:selectItem itemValue="" itemLabel="---"/>
<f:selectItems value="#{bookCtrl.books}" var="b"
itemValue="#{b.isbn}" itemLabel="#{b.title}"/>
<f:ajax listener="#{bookCtrl.refreshObject( book)}"
render="isbn title year" />
</h:selectOneMenu>
</h:outputLabel></div>
<div><h:outputLabel for="isbn" value="ISBN: ">
<h:outputText id="isbn" value="#{book.isbn}"/>
</h:outputLabel></div>
<div><h:outputLabel for="title" value="Title: ">
<h:inputText id="title" value="#{book.title}"/>
</h:outputLabel></div>
<div><h:outputLabel for="year" value="Year: ">
<h:inputText id="year" p:type="number"
value="#{book.year}"/>
</h:outputLabel></div>
<div><h:commandButton value="Save Changes"
action="#{bookCtrl.update(
book.isbn, book.title, book.year)}"/>
</div>
</h:form>
</ui:define>
</ui:composition>
</html>In this facelet template, a single selection list (that is, a
single-select HTML element) is created with the help of the
JSF element h:selectOneMenu, where the selection list items
(the HTML option elements) are defined by the JSF elements
f:selectItem or f:selectItems. The
value attribute of h:selectOneMenu binds
book.isbn to the value of the selected item (or
option element). The selection list is populated with book
records with the help of a f:selectItems element bound to
bookCtrl.books. The attributes itemLabel and
itemValue define the option elements' text and
value.
In the update view, when the user selects a book from the selection
list, the form fields are filled with the (ISBN, title and year) property
values of the selected book. While the ISBN is immediately available in
the view (on the front-end) as the value of the selected
option element, the values of the title and
year properties have to be fetched from the back-end
database. This can be done with the help of the JSF element
f:ajax, which sends an HTTP request message for invoking a
remote method, bookCtrl.refreshObject, on the back-end using
XHR. This method takes the managed book bean, and
updates its title and year properties with the
current values retrieved from the database. Its code is the
following:
public class BookController { ... public void refreshObject( Book book) { Book foundBook = Book.retrieve( em, book.getIsbn()); book.setTitle( foundBook.getTitle()); book.setYear( foundBook.getYear()); } ... }
To enforce a refresh of the HTML form after the user's selection,
such that it displays the values of isbn, title
and year, the f:ajax element allows specifying
form fields to be updated with the render attribute like, in
our case, render="isbn title year".
Finally, the h:commandButton element is used for
invoking the update action method of the
BookController with the parameters isbn,
title and year, for making the changes
persistent.