Using Subforms with betterFORM
This article gives a short introduction to using subforms with betterFORM. Before going into details it should be clarifed what is meant when talking about subforms. Subforms are complete self-contained pieces of markup consisting of a XForms model and its associated UI that are loaded at runtime with the help of the XForms load action.
In the majority of cases XForms markup is embedded inside a XHTML document (other markup languages are of course also possible as host document). In this respect subforms don’t differ from ‘normal’ XForms documents.
However we use a convention for the structure of the document: we put the XForms model and user interface into one div within the body of the document like so:
<html> <head><title>A sample form</title></head> <body> <div id="xforms"> <xf:model id="mymodel"> ... <xf:group> ... </div> </body>
This is perfectly in sync with the XForms Spec. It’s a mere convention that some people put their models into the head section. Putting both the model and the UI into a div in the body just makes it easier to embed the form in one go instead of needing two or more instructions. It may be advisable to wrap the model in another div and hide it from the browser with style=”display:none;” (not shown here). This avoids that the browser chokes on the unexpected XML markup.
A complete example illustrate best how easy it is to use subforms. The following piece of code shows how to use the XForms load action to embed a complete XForms model:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"> <head> <title>an embed sample</title> </head> <body> <div> <xf:model id="model"> <xf:instance xmlns=""> <data/> </xf:instance> </xf:model> <xf:group> <div id="embeddedForm"/> <xf:trigger id="trigger-load-embed"> <xf:label>Load embedded Form</xf:label> <xf:action> <xf:load show="embed" targetid="embeddedForm"> <xf:resource value="'EmbeddedForm.xhtml#xforms'"/> </xf:load> </xf:action> /xf:trigger> </xf:group> </div> </body> <</html>
There are a few things worth pointing out. First note the <div id=’embeddedForm’/>. This is be the element that gets replaced by the subform once the trigger has been activated. Second, look closely at the <load> element. While XForms only know the values ‘new’ and ‘replace’ for the show attribute betterFORM also handles the value ’embed’. The additional attribute ‘targetid’ specifies an idref to the element that will get replaced by this action. The resource element finally specifies the subform document. The fragment identifier (‘#xforms’) is another idref pointing to the target element within that document. By using a fragment identifier it is possible that the subform resides in its own complete document and can be run and tested independently from the embedding document.
The following things happen when the load action is run:
- the resource will get loaded and parsed as XML
- the element denoted by the ‘targetid’ attribute will be extracted
- the resulting subtree is imported into the calling document
- the XForms processor will initialize the subform by looking for models within the loaded markup
- the lifecycle events defined by XForms (model-construct, model-construct-done and xforms-ready) are dispatched to initialize the subform just as any ‘normal’ form
- the subform will be rendered as part of the original page calling the load
Once you have loaded a subform you will probably want to get rid of it later when its purpose is done. This can easily be done with the following markup:
<xf:load show="none" targetid="embeddedFom"/>
- working with subforms allows easier authoring and testing of large form-based applications
- loading of subforms is fast as they are processed by just one instance of a XForms processor
- resource consumption is much lower compared with big forms that use a XForms switch to show / hide specific views
- this extension of the load action is not yet part of the XForms standard but hopefully will become in one of the future versions
A more in-depth documentation of this feature can be found in the betterFORM User Guide.