This section lists some unsorted tips that have evolved over the years of working with XForms to avoid common pitfalls.
Use Id Conventions
This is a rather obvious tip but nevertheless should not be missing here: always use speaking ids and choose thoughtful names as you would do in any other programming language. As XForms uses a lot idrefs it also helps to apply some patterns to your ids. Over the years we have become used to the following patterns:
- prefix model ids with “m-” e.g. “m-address”
- prefix instance ids with “i-” e.g. “i-default”
- prefix submissions ids with “s-” e.g. “s-save”
- prefix bind ids with “b-” e.g. “b-street”
- prefix repeat ids with “r-” e.g. “r-phones”
However we do not prefix UI Controls. This would lead to too much prefixes and also introduce ambiguities.
Add actions for submission events
Always add actions for “xforms-submit-done” and “xforms-submit-error”. Otherwise you will be left without a clue what has happened with your submission – what it successful or did an error occur?. A simple ephemeral message gives you clarity:
<xf:submission (...) > <xf:message level="ephemeral" ev:event="xforms-submit-done">Everythings fine!</xf:message> <xf:message level="ephemeral" ev:event="xforms-submit-error">Oops - something went wrong</xf:message> </xf:submission>
Group related things together
This is rather common-sense but related things should be grouped together in your form to make it more readable. Also use comments! to structure your markup. E.g. we always put bindings that belong to a certain instance directly after that instance and also put submissions of a certain instance below the bindings. A simple example:
<!-- ########## instance 'i-default' ########## --> <xf:instance id="i-default"> (...) </xf:instance> <xf:bind nodeset="instance('i-default')"> <xf:bind (...) (... more bindings to instance 'i-default' ...) </xf:bind> <xf:submission id="s-save" ref="instance('i-default')" (....) /> <!-- ########## instance 'i-another' ########## --> <xf:instance id="i-another"> (...) </xf:instance> <xf:bind nodeset="instance('i-another')"> (...) </xf:bind> <xf:submission id="s-save-another" ref="instance('i-another')" (....)
Avoid (too) large forms
To a certain extend big forms are ok. But if a form grows bigger than 1000 or probably even several thousand of lines of markup you should begin to think about breaking it down to pieces. This is good practice for any programming language and also applies to XForms. XForms is a powerful tool and as this you can abuse it but also create nicely modularized pieces of markup.
XForms allows an unlimited amount of models within your document. Use this capability to tailor your forms. This will have major impact on reusability and performance as the rather expensive rebuild, recalculate, revalidate, refresh cycles run per model – many smaller models will perform much better than one giant form that handles all at once.
If that doesn’t help enough please refer to Chapter 6 and try dynamic loading of subforms. Users have a limited capacity with regard to the amount of information they can handle at once therefore it’s better anyway to only present smaller groups of controls.
Use UI bindings
XForms knows two flavors of bindings: UI bindings and model bindings. The former are represented by the Attributes nodeset or ref while the latter come as bind Elements. Bind elements are mainly used to attach constraints to instance nodes but can also be referenced from the UI.
Example of model / UI binding:
... <xf:instance> <bar xmlns=““/> </xf:instance> <xf:bind id=“foo“ nodeset=“/bar“ /> ... <xf:input bind=“foo“ id=“model_binding“> ... <xf:input ref=“/bar“ id=“ui_binding“> ...
The input control ‘model_binding’ references the bind Element ‘foo’. This attaches the node referred by the nodeset Attribute of the bind (foo) to the input control. In other words: the input indirectly binds to the instance. The bind Element will be the middle man.
Generally this is fine though it sometimes leads XForms beginners to the wrong assumption that referencing the bind from the input control is needed to attach the constraints specified on the bind. This is plain wrong: any MIP defined on a bind will be attached to nodes referenced by the nodeset attribute regardless of it being referenced by a UI control or not.
The problem with using model bindings comes when hand-authoring large forms. You always have to follow the indirection to know where a control binds to in the instance and which calculations and constraints are in place. This can take significant time of your development work. With the arrival of powerful XForms editors this problem should one day be solved.
UI bindings are easier to manage and quicker to understand. And by using scoped addressing the pathes won’t get that long.
Example scoped addressing:
<xf:group ref=“instance()“> <xf:group ref=“address“> <xf:input ref=“street“>
The bound node for the input will be ‘instance()/address/street’.
Don’t forget about namespaces
Namespaces are a pain for many people though once they are in place there’s nothing mysterious about them and you can easily leave them alone. To avoid problems put all the namespaces you want to use on the root node of your document. Then in case you know where you have to search.
Don’t forget the default namespace
A very common mistake when writing XForms is to forget the empty namespace declaration on an instance. Any instance that does not use a specific namespace should look like this:
<xf:instance> <data xmlns=““>
Alternatively you can put the declaration on the instance Element itself.
Avoid mixing of ui logic and form purpose
When developing complete applications in XForms you’ll get a mixture of XForms markup that deals with the logic of the application UI and markup that deals with the actual purpose of the form (e.g. collecting addresses).
For instance, you may control access of certain controls by hiding/showing them, use XForms controls to implement wizard logic or activate/deactivate controls depending on some application mode.
You should be aware of this and plan ahead if your UI logic starts to get complex. Try to factor out a separate model for the UI logic to keep different things separate.