In this step we will create the editable person subform and show both the person and address subform on one web page.

The resulting page

contains 2 subForms: persons and their addresses

contains a search filter for person wildcard searches

supports navigation from person to address through a navigation link

Both subForms contain the full editing / sorting / paging facilities. The resulting page will look like this:

Let's have a look step by step.

Creating the person subform

We have already created the address subform and this one comes pretty close. Have a look at the final /WEB-INF/tags/segments/tables/persons.tagx here. This extract shows the segment definition for persons target subform:

We already know that the entityClass property denotes the class of the objects in the resultset. The filterClass specifies a filter for populating the persons data grid with the users selection. Note that if we need individual formatting for rows in our data grid we can easily override the default bindings to achieve for example a different nationalized time date granularity.

Specifying a filter

Definition

Shept supports all kinds of Hibernate filters e.g. the criteria API, the query API as well as entity examples and relationships from your generated or defined relationships. In this case we use the criteria API. The PersonFilter inherits from the HibernateCriteriaFilter which by default takes the entityClass definition to create a new empty row instance. (If we don't want to allow creation of a new Person we need to override the #getNewModelTemplate to return null). This is the interesting part from the PersonFilter.java:

Note that the path specification matches the property accessors of the underlying PersonFilter.java class.

Registration

Again we need to register the person subform to bind the person segment configuration to its view.The following snippet from /WEB-INF/tags/segments/segments.tagx binds the person data grid and the filter:

<!-- chains from unitsFiltered (same as targets but also a source)--><beanparent="sheptChain"><propertyname="from"ref="persons"/><propertyname="to"ref="addresses"/><propertyname="info"><beanparent="sheptInfoItem"p:code="info.addresses"p:selector="name"/></property></bean>

</util:list>

</beans>

The from and to properties refer to the corresponding segment definitions in segments.xml. Two things are important to note: 1) The specified chain name addresses refers to the target segment named addresses. If the target would be used in more than one context resulting in ambigous names we need to name the <bean parent="sheptChain" name="myChainName" > and use myChainName in <table:chainRow chainName="myChainName"> instead of addresses as the chain name.2) The targets segments name serves as the default accessor method name for traversing the relation from Person to Address. If thats not suitable or you just want to have your naming conventions depending on each other you can specify a relation name as a property: <property name="relation" value"addresses" />

The info property binds an informal message code to a selector of the referring entity so that the result will show like this .

Full CRUD support

The dependent addresses data grid supports the full CRUD lifecycle. While read / update / delete are not surprising the creation of new entity instances is also supported. 2 conditions need to be met:

The class of the target entity Address needs to support initialization from the depending entity. For this we will implement an Address#initialize(Person) method:

publicvoidinitialize(Person person){this.person= person;}

So when you click on the chain in one Person row a new template of Address will be created and initialized with that Person.Now we have created a template object that can be used as a new instance provided the users enters more specific data into that row.We need to define under which circumstances it should be allowed to save this new entity. For this purpose we need to define the ModelCreation interface on the Address object:

The #isCreationAllowed(Object) method is to compare an empty template (=this) with the edited candidate row (argument object) for saving if the users has entered enough additional information to allow saving. You need to define your own rules on each entity to allow saving.

The #isTransient() serves as a simple to use indicator if the underlying entity should be treated as a new row candidate primarily for decorating a new row in the view.