A FormFragment is a portion of a Form that may be selectively displayed. Form elements inside a FormFragment will automatically bypass validation when the fragment is invisible. The trick is to also bypass server-side form processing for such fields when the form is submitted; client-side logic "removes" the form data for the fragment if it is invisible when the form is submitted; alternately, client-side logic can simply remove the form fragment element (including its visible and hidden fields) to prevent server-side processing. The client-side element has a new property, formFragment, added to it. The formFragment object has new methods to control the client-side behavior of the fragment: hide() Hides the element, using the configured client-side animation effect. hideAndRemove() As with hide(), but the element is removed from the DOM after being hidden. show() Makes the element visible, using the configured client-side animation effect. toggle() Invokes hide() or show() as necessary. setVisible() Passed a boolean parameter, invokes hide() or show() as necessary.
| Name | Type | Flags | Default | Default Prefix | Description |
|---|---|---|---|---|---|
| element | String | NOT Allow Null | literal | The element to render for each iteration of the loop. The default comes from the template, or "div" if the template did not specific an element. | |
| hide | String | NOT Allow Null | literal | Name of a function on the client-side Tapestry.ElementEffect object that is invoked when the fragment is to be hidden. If not specified, the default "slideup" function is used. | |
| show | String | NOT Allow Null | literal | Name of a function on the client-side Tapestry.ElementEffect object that is invoked to make the fragment visible. If not specified, then the default "slidedown" function is used. | |
| visible | boolean | NOT Allow Null | prop | Determines if the fragment is intially visible or initially invisible (the default). This is only used when rendering; when the form is submitted, the hidden field value is used to determine whether the elements within the fragment should be processed (or ignored if still invisible). |
Informal parameters: supported
Clicking the checkbox will trigger an animation that slides down the remainder of the form.
The FormFragment component ensures that client-side validation is only enabled for fields that are actually visible to the user. In addition, for fields that are enclosed within the FormFragment, server-side validation and processing only occurs if the fields were visible to the user when the client-side form was submitted.
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<body>
<h1>Order Address</h1>
<t:form>
<t:errors/>
<div class="t-beaneditor">
<h2>Billing Address</h2>
<t:beaneditor t:id="billingAddress"/>
<t:checkbox t:id="separateShipTo" t:mixins="triggerfragment" fragment="seperateShippingAddress"/>
<t:label for="separateShipTo">Separate Ship To?</t:label>
<t:formfragment t:id="seperateShippingAddress" visible="separateShipTo">
<h2>Shipping Address</h2>
<t:beaneditor t:id="shippingAddress"/>
</t:formfragment>
<div class="t-beaneditor-row">
<input type="submit" value="Continue"/>
</div>
</div>
</t:form>
</body>
</html>The separateShipTo property is initially null, so the FormFragment is initially invisible. The BeanEditor and all of the individual fields are rendered, but the <div> for the FormFragment is simply invisible.
The TriggerFragment mixin adds a client-side trigger that will show or hide the fragment as the checkbox is clicked by the user.
public class OrderAddress
{
@Persist
private ShippingAddress _billingAddress;
@Persist
private ShippingAddress _shippingAddress;
@Persist
private boolean _separateShipTo;
public ShippingAddress getBillingAddress()
{
return _billingAddress;
}
public void setBillingAddress(ShippingAddress billingAddress)
{
_billingAddress = billingAddress;
}
public ShippingAddress getShippingAddress()
{
return _shippingAddress;
}
public void setShippingAddress(ShippingAddress shippingAddress)
{
_shippingAddress = shippingAddress;
}
public boolean isSeparateShipTo()
{
return _separateShipTo;
}
public void setSeparateShipTo(boolean separateShipTo)
{
_separateShipTo = separateShipTo;
}
}The OrderAddress page is largely just a holder of the properties (for simplicity in this example, there is no event handler for the success event, nor are we going into other details that would be reflected in a real application).
The BeanEditor component will create default instances of billingAddress and shippingAddress. If the user does not choose to use a seperate ship-to, the shippingAddress property will contain an empty ShippingAddress object. The application will need to query the separateShipTo property to determine how to proceed once the form is succesfully submitted.
FormFragments are nestable, which can lead to complex (and perhaps, confusing) interfaces.
The FormFragment doesn't just prevent server-side input validation when invisible; it prevents any server-side processing for the components it encloses, as if the components were entirely absent.
If JavaScript is disabled on the client, the application will still operate, though the user will have to submit the form to have the fragment(s) update.