|
The big win of the separation of concerns that pageflow
enables is that you can easily update the flow logic without the changes rippling
through your application. In this section, we will enhance the new hotel creation
flow to allow the user to select a hotel as a starting point. This might be useful
creating multiple hotels in the same city or multiple hotels in the same chain. To
do this, we'll update the pageflow as shown here, adding a new list state and a
clone transition from the edit page.
<start-page name="edit" view-id="/newHotel.xhtml">
<redirect/>
<transition name="proceed" to="confirm" />
<transition name="clone" to="list" />
</start-page>
<page name="list" view-id="/newHotelList.xhtml">
<redirect />
<transition name="select" to="edit">
<action expression="#{newHotel.copySelected}" />
</transition>
<transition name="cancel" to="edit" />
</page>
This
list page can return to the edit page in two ways. In one transition, it copies a
hotel definition back using the copySelected method on newHotel. To implement this,
need to add the following code to NewHotelAction.java. Make sure to update the
NewHotel.java interface to add the new methods.
@DataModel List<Hotel> allHotels;
@DataModelSelection Hotel selectedHotel;
@Factory("allHotels")
public void findAllHotels() {
allHotels = em.createQuery("from Hotel").getResultList();
}
public void copySelected() {
hotel.setName(selectedHotel.getName());
hotel.setAddress(selectedHotel.getAddress());
hotel.setCity(selectedHotel.getCity());
hotel.setState(selectedHotel.getState());
hotel.setZip(selectedHotel.getZip());
hotel.setCountry(selectedHotel.getCountry());
}
Not only have we added copySelected, we've also added an allHotels component that will contain a list of all the hotels in the
system. Whenever the a view asks for allHotels, it will be provided by newHotels, using the corresponding @Factory method to initialize the list. The @DataModel and @DataModelSelection annotations provide hooks
for Seam's data binding framework to link to a JSF dataTable. We'll use allHotels in the new newHotelList.xhtml. Create this view using
the sample page template and put the following into the content section:
<div class="section">
<h1>Select a Hotel to Copy</h1>
<h:dataTable value="#{allHotels}" var="hot">
<h:column>
<f:facet name="header">Name</f:facet>
#{hot.name}
</h:column>
<h:column>
<f:facet name="header">Address</f:facet>
#{hot.address}
</h:column>
<h:column>
<f:facet name="header">City, State</f:facet>
#{hot.city}, #{hot.state}, #{hot.country}
</h:column>
<h:column>
<f:facet name="header">Zip</f:facet>
#{hot.zip}
</h:column>
<h:column>
<f:facet name="header">Action</f:facet>
<s:link value="Copy" action="select"/>
</h:column>
</h:dataTable>
<h:form>
<div class="entry">
<div class="label"><f:verbatim> </f:verbatim></div>
<div class="input">
<h:commandButton value="Cancel" action="cancel" class="button" /> 
</div>
</div>
</h:form>
</div>
This is a
simple table which displays the allHotels
data in table form. (notice that the data and events are completely decoupled from
the underlying components) The last column of each table triggers the select
transition, which calls the copySelectedHotel method on newHotel. Because of the @DataModelSelection annotations, Seam automatically sets the selectedHotel value to the hotel
corresponding to the row of the data table being used. The cancel button at the
bottom is not related to the data table in any way. It just triggers the pageflow to
return to the first page.
The very last step is to add a button to the view
which will take the user to the list screen from the new hotel page. It's important
that you set immediate="true" on the button
to make sure that action executes without setting the form values and triggering
validation errors from the blank fields.
<h:commandButton value="Copy Existing" action="clone" immediate="true" class="button" />
At this point, you can
deploy the new version of the application and test out the new pageflow.
|