Demo: Persons and Adresses » Create Address Subform

Create Address Subform

Last modified by Andreas Hahn on 2011/05/30 17:42

Let's create a simple project maintaining addresses.

Segment configuration

In /WEB-INF/segments.xml we will create a minimal segment configuration:

<bean name="addresses" parent="sheptDataGridTemplate">
   <property name="entityClass" value="org.shept.apps.demo.orm.Address" />
   <property name="componentPostprocessor" ref="commonPostProcessor" />
</bean>
<bean id="commonPostProcessor"
   class="org.shept.apps.demo.web.controller.postprocessors.CommonPostProcessor" >
</bean>

We have defined segment named addresses. It is of type sheptDataGridTemplate which is the default type for table based segments. It's class is defined with all the other defaults in shept.xml. We have also define a property entityClass with an address entity class meaning that the resulting table is populated with instances of this class. We also need a postprocessor for populating the address type choices.

DataGrid View creation

The view contains of 3 parts:

  • header (attribute tabHeader)
  • row content (attribute tabRow)
  • submission options (attribute tabSubmit)

Save the final result as address.tagx in the projects /WEB-INF/tags/segments/tables directory.

<jsp:root
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:spring="http://www.springframework.org/tags"
xmlns:form="http://www.springframework.org/tags/form"
xmlns:table="http://www.shept.org/tags/table"
xmlns:shept="http://www.shept.org/tags/shept"
version="2.0"
>

<table:table >
 <jsp:attribute name="tabHeader" >
<tr class="sheptTableHeader">
<th />
<th nowrap="nowrap" >
  <table:sort sortCol="person.firstName" code="person.firstName" />
</th>
<th nowrap="nowrap" >
  <table:sort sortCol="person.name" code="person.name" />
</th>
<th nowrap="nowrap" >
<table:sort sortCol="addressType" code="address.type" />
</th>
<th nowrap="nowrap" >
<table:sort sortCol="country" code="address.country" />
</th>
<th nowrap="nowrap" >
<table:sort sortCol="city" code="address.city" />
</th>
<th nowrap="nowrap" >
<table:sort sortCol="zipcode" code="address.zip" />
</th>
<th nowrap="nowrap" >
<table:sort sortCol="street" code="address.street" />
</th>
<th nowrap="nowrap" >
<table:sort sortCol="number" code="address.number" />
</th>
<th />
<th />
</tr>
 </jsp:attribute>
 
 <jsp:attribute name="tabRow" >
<tr class="${rowClassDefault}">
<td>
<table:iconRow />
</td>
   <td>
<form:input path="person.firstName" disabled="true" cssErrorClass="sheptFieldError" />
</td>
<td>
<form:input path="person.name" disabled="true" cssErrorClass="sheptFieldError" />
</td>
<td>
<form:select path="addressType" >
<form:option value="" label="---" />
<form:options items="${addressTypes}" />
</form:select>
</td>
<td>
<form:input path="country" cssErrorClass="sheptFieldError" />
</td>
<td>
<form:input path="city" cssErrorClass="sheptFieldError" />
</td>
<td>
<form:input path="zipcode" cssErrorClass="sheptFieldError" />
</td>
<td>
<form:input path="street" cssErrorClass="sheptFieldError" />
</td>
<td>
<form:input path="number" cssErrorClass="sheptFieldError" />
</td>
<td>
<table:confirmDeleteRow />
</td>
</tr>
 </jsp:attribute>

 <jsp:attribute name="tabSubmit" >
  <shept:submission />
 </jsp:attribute>
</table:table>

</jsp:root>

A few notes on what's goin on here:

The handlers for the namespaces 'shept' and 'table' are bundled within the shept.jar.
The handlers for the namespaces 'spring' and 'form' are defined wihtin the spring framework.

TabHeader

In the tabHeader section we define the column headers for the table. The <table:sort /> statements indicate that the row is sortable. Attribute sortCol refers to the attributes of the entity object class that we have defined in the segment configuration. Note that dotted path names 'person.firstName' denote that your address object contains a person object and the list shall be sorted by the indirection of the address persons firstName.

TabRow

In the tabRow section we define the rows bindings. The <form:input /> statements are bindings from the spring framework. Again each path - attribute must correspond with an attribute of the entity object class defined in the segment configuration. Again a dotted path is allowed. We intend dependent objects to be immutable in this context (as we do not want to have conflicting data in the different rows) so we define these fields disabled="true". The cssErrorClass refers to a css class that will be included when the form is rendered in case of form binding errors (type mismatches, form validation errors, thrown exceptions, ...).
The <form:select /> statement allows selection of an option from a choice list. The list needs to be defined as a postprocessor in the segment configuration.
Note the <table:iconRow /> statement at the beginning an the <table:confirmDeleteRow /> statement at the end. These are convenience inclusions to mark a row as a new data entry row and to prepare a row for deletion.

TabSubmit

With <shept:submission/> we have introduced the default submission options (segment save and refresh).

Subform Registration

As a final step we need to register the view and bind it to its segment configuration.
We need edit the registration template /WEB-INF/tags/segments/segments.tagx. adding a handler for <table:address /> view within the <c:choose ></c:choose> brackets:

<c:when test="${subFormName eq 'addresses'}">
 <shept:subForm headerCode="addresses" >
<table:address />
 </shept:subForm>
</c:when>

Choice list postprocessor

This is a simple postprocessor for populating the choice listbox.
Save the file in org.shept.apps.demo.web.controller.postprocessors as CommonPostProcessor.java.
This is sort of traditional style Spring MVC SimpleFormController#referenceData with an additional segment identifying parameter componentPath.

package org.shept.apps.demo.web.controller.postprocessors;
/**
 *
 */


import java.util.LinkedHashMap;
import java.util.Map;

import org.shept.org.springframework.web.bind.support.ComponentPostprocessor;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.support.WebApplicationObjectSupport;
import org.springframework.web.servlet.ModelAndView;

/**
 * @version $$Id: $$
 *
 * @author Andi
 *
 */

public class CommonPostProcessor extends WebApplicationObjectSupport implements
ComponentPostprocessor {

/* (non-Javadoc)
* @see org.shept.org.springframework.web.bind.support.ComponentPostprocessor#postHandle(org.springframework.web.context.request.WebRequest, org.springframework.web.servlet.ModelAndView, java.lang.String)
*/

@Override
public void postHandle(WebRequest request, ModelAndView mv,
String componentPath) {

if (mv != null) {
mv.addObject("addressTypes", getAddressTypes(getMessageSourceAccessor()));
}
}

private Map<Integer, String> getAddressTypes(MessageSourceAccessor accessor ) {
Map <Integer, String> modes = new LinkedHashMap <Integer, String>();
modes.put(0, "default address");
modes.put(1, "shipping address");
modes.put(2, "legal address");
return modes;
}

}

Note that list of addressTypes is exposed under the key addressTypes  which is referred in the  <form:options items="${addressTypes}" /> statement in address.tagx.

WebPage Registration

Your web page needs to be registered. Configuration is done in WEB-INF/sheptDemo-servlet.xml shown on the next page

Result

See a screenshot of the resulting page

SheptDemoAddresses.png

General Setup >>

Tags:
Created by Andreas Hahn on 2010/12/14 14:52

© 2011 shept.org - Andreas Hahn