7.2 XForms Actions

The following sections describe all of the XForms Actions defined in XForms. Any of the following can be invoked in such a way that the processing described for the element happens in response to a given event.

message

This action directs a message to the user, with various possible levels of intrusiveness, based on the required attribute level. In scripting, this effect is commonly implemented with the alert( ) function, which is the most intrusive technique, since it is modal, and prevents any further action until the user dismisses the message. XForms enables friendlier (and less visual-centric) messages: modeless, which doesn't interfere with the rest of the form, but sticks around until dismissed; and ephemeral, a fleeting, goes-away-by-itself message, such as a tool tip or brief status bar message.

Figure 7-2 shows visual representations of various messages.

Figure 7-2. XForms Action: message
figs/xfe_0702.gif

The general concept of various levels of intrusiveness applies well to non-visual designs, too; for example, the difference between an insistent voice prompt that requires acknowledgement versus a one-time message.

Typically, the content of the message element is the message to be rendered. Like other XForms elements, the content can also come from the instance data (from binding attributes) or from an external file (from linking attributes). Only a single source is ever used; the order of preference is: binding attributes, linking attributes, inline text, as shown next.

<message level="ephemeral" ev:event="DOMFocusIn">Produced by PBP</message> <message level="modeless" model="messages" ref="instructions/part3"                 ev:event="xforms-help"/> <message level="modal" src="/books/2/308/1/html/2/important.html" ev:event="DOMActivate">
setvalue

Binding attributes on this element select the location in the instance data to receive the value, which is always simpleContent. Note that XForms doesn't include a way to arbitrarily alter complexContent through XForms Actions, though the insert and delete actions can to a limited extent.

Another job commonly reserved for scripting is to set values in the form, as shown in the earlier example in this chapter. This action can set the value of an attribute node or an element's text node, to either a fixed value or the result of evaluating XPath.

The value to place in the instance is either an XPath expression, contained in the value attribute, or literal text as the content of the element. If both should happen to be present, the evaluated XPath is used.

Clearing a value is the same as setting a zero-length string in other words, neither a value attribute nor element content.

setvalue can be useful in several contexts, as shown here:

<!-- on initialize, set a value of "0" --> <setvalue bind="frequency" ev:event="xforms-ready">0</setvalue> ... <!-- on initialize, copy the billing address to the shipping address --> <setvalue ref="Shipping/Addr" value="../Billing/Addr"                ev:event="xforms-ready"/> ... <!-- clear a value when an Insert happens --> <setvalue bind="phone_num" ev:event="xforms-insert"/>
setfocus

This action redirects the focus to a different form control. An attribute named control holds an IDREF of the form control that will get focus.

In effect, this action does nothing more than dispatch an xforms-focus event to the form control indicated. It can be used like this:

<setfocus control="Address_1" ev:event="xforms-ready"/>
send

This action invokes submission of a form. A required attribute submission holds an IDREF to a submission element that contains the details of what and how to submit.

The effect is the same as dispatching an xforms-submit event to the submission element indicated. Details of submit options are discussed in Chapter 8.

<send submission="submis3" ev:event="DOMActivate"/>
reset

A reset control is probably the most overused form control on the web. (This is why XForms doesn't define a reset control) Still, in the right circumstances, it's necessary to reset a form, which is what this action does. It takes an attribute model, which contains the IDREF of the model element that will be reset.

The reset condition is defined as the state the instance data was in immediately after the xforms-ready event was dispatched. reset can be used like this:

<reset model="weather" ev:event="DOMActivate"/>
load

This action traverses a link, possibly in a new window (or browsing context for non-visual devices), possibly replacing the active form. The optional attribute show, which can have a value of either "new" or "replace", determines the behavior.

The URL that the link goes to can either be specified in the resource attribute, or it can be in the instance data, pointed to by binding attributes (bind, or ref optionally with model).

Never include both linking attributes and a resource attribute since having both is an invalid combination, that results in the load action having no effect at all.

Two ways to use the load action are like this:

<load resource="http://www.example.com" ev:event="DOMActivate" show="replace"/> <load ref="linktable/nextpage" ev:event="DOMFocusOut" show="new"/>
toggle

This action works with a switch element, selecting by IDREF a particular case within. The selected case is rendered, while all other cases are not. The ability to show and hide sections is a handy way to implement a "multiple page" form, which guides the user through one section at a time. It's also useful within a page, to set up wizard-like sequences, or just to hide entire sections of the form that aren't needed at the moment.

Each case contains a selected attribute, which stays in sync, so that at any given time one and only one of the cases in a switch will have selected="true". In fact, in systems that support CSS2 selectors, one possible implementation is with the rule case[selected="false"] { display: none }.

The toggle action is used like this:

<toggle case="summary" ev:event="DOMActivate"/>
insert

This action works within a node-set, by constructing new nodes based on a template. The immediate problem with this approach is that if there are no nodes present in the repeating set (as can happen after invoking the delete action), what template can be used to copy from? The answer depends on the way instance data is constructed in XForms: as a separate in-memory representation. The initial instance data, as it appears inside the instance element in the containing document (or in an external linked file) doesn't change as the instance data changes through all the various interactions defined by XForms. Thus, the initial instance data is defined as the source of the template to be copied, even though it makes for some awkward terminology to explain how it works.

The main attributes that control the operation of this element are:

single-node binding attributes

These attribute or attributes select a node-set, which matches the node-set selected by a repeat set.

at

This attribute selects the location within the node-set where the inserted element node will appear. Generally, it is one of three possibilities:

  • To insert a new repeat item at the beginning, at="1".

  • To insert a new repeat item at the end, at="last( )".

  • To insert a new repeat item at the current index, at="index('id_of_repeat')" (where id_of_repeat represents the IDREF of the <repeat> element).

position

This attribute is required, and must be either "before" or "after" where to insert the new node relative to the node selected by at.

The at attribute is evaluated as an XPath number, which creates a few edge cases that need to be addressed:

  • Negative or zero results are treated like "1".

  • Results larger than the size of the node-set, or that can't be interpreted as a number at all, are treated like "last( )".

  • Fractional results are treated as if passed through a call to the XPath core function round( ), so that "1.5" becomes 2.

Once the location for the new node is determined, a new element node is manufactured by parsing the corresponding portion of the initial instance data, taking the final node present, which is deep copied into the instance data. This example demonstrates:

<model>   <instance>     <order xmlns="">       <items>         <item price="1.00"/>         <item price="2.00"/>         <item price="3.00"/>       </items>     </order>   </instance> </model> ... <repeat  nodeset="order/items/item">   <input ref="@price">     <label>Price</label>   </input> </repeat> ... <trigger>   <label>Insert a new item after the current one</label>   <action ev:event="DOMActivate">     <insert nodeset="/order/items/item" at="index('repeat_id')" position="after"/>     <setvalue ref="/order/items/item[index('lineset')]/@price"/>   </action> </trigger>

In this example, every time an insert action happens, the element node that gets copied is the one that reads <item price="3.00"/>, being the final member of the repeat set in the initial instance data. This is true no matter what insertions or deletions happen to the instance data. This example also shows following an insert with a setvalue, to give the newly-inserted node a desired value (in this case, empty).

Another question that comes up is what model item properties apply to the newly-inserted nodes. All bind expressions that point into the repeat set are reevaluated, so the model item properties can be applied equally to the new nodes.

As a typical result of insert, a new repeating item will be rendered in the user interface. The newly-inserted repeat item also becomes the repeat index, effectively giving focus to the new content.

delete

This action is the counterpart of insert it removes nodes from the instance data. Without the issues of copying nodes from a template, the overall operation of this element is much simpler.

This element also has an attribute named at, which operates the same way as insert. It identifies an element node that is removed, along with any associated nodes (content text nodes, child element nodes, attribute nodes, and so on). The corresponding user interface for the repeat will also adjust to the now smaller repeat set.

This example continues the example in the previous section:

<trigger>   <label>Remove current item</label>   <delete ev:event="activate" nodeset="/order/items/item"    at="index('repeat_id')"/> </trigger>
setindex

Every repeat set keeps track of a current item, similar to a database cursor. The official term for this is the index. The index item behaves for multiple form controls much as a focus behaves for single form controls. In fact, setting the focus to a form control in a repeat set also adjusts the index to that spot. This action explicitly changes the index.

Two attributes control the behavior of this element: repeat, which takes an IDREF of a repeat set, and index, which takes an XPath expression that evaluates to a number, just as the as attribute on insert and delete.

setindex is used like this:

<setindex repeat="repeat_id" index="1" ev:event="xforms-ready"/>
revalidate, recalculate, refresh, and rebuild

XForms keeps track of computational dependencies, like a spreadsheet, so that any chained calculations properly resolve themselves in the face of changes. This action explicitly invokes a rebuilding of the dependencies, and is almost never needed.

These four actions trigger the processing involved with revalidation, recalculation, refresh, and rebuilding dependencies, respectively. Under normal conditions, all of these activities take place automatically, and form authors don't even need to consider these events or actions.

The primary exception, however, is on limited platforms where any of these activities might be expensive, in terms of processing or perceived user delay. When that's the case, it's not desirable for these events to happen automatically. Instead, users will want to have greater control over exactly when such things happen. This is similar to the concept of spreadsheets that have an option to turn off automatic recalculation.

To do this in XForms is a two-step process. First, an observer needs to be set up to cancel all automatically generated events for the expensive process (recalculation in this example). That step, by itself, will result in the recalculation never happening, which doesn't work so well. So the second step is to provide an option for the user to manually fire off a recalculate. This example shows both aspects:

<model ev:event="xforms-recalculate" ev:defaultAction="cancel"> ... <trigger>   <label>Recalculate now</label>   <recalculate ev:event="DOMActivate"/> </trigger>

Note that this works because the recalculate action directly invokes the processing, without the intervening event flow (which would get cancelled by the observer on model anyway).

dispatch

This action dispatches any event to any element. In a sense, this is the most powerful XForms Action since, through events, nearly anything can be done.

This element contains four special attributes. The two required attributes are name, which names the event, and target, which holds the IDREF of the element that will be the target of the event. Two other optional attributes (bubbles and cancelable) specify whether the event can bubble or be cancelled, though all the predefined events have their own specification and can't be overridden.

An advanced technique is to create custom events, which can be dispatched and observed to accomplish specific behaviors, like this:

<dispatch name="xforms-refresh" target="model3" ev:event="DOMActivate"/> <dispatch name="show-easter-egg" target="listener9" cancelable="false"                 ev:event="my-custom-evt"/>
action

This element is a wrapper for other XForms Actions. It contains child elements that are executed in sequence.

action can be used like this:

<action ev:event="DOMActivate">   <setvalue ref="email/contact" value="email/admin"/>   <message level="ephemeral">Synchronized email addresses</message> </action>

One concept that comes into play in more advanced XForms scenarios is what the specification calls "deferred updates." This feature is intended to reduce the potentially expensive computation that can occur through an XForms Action, as changes to the instance data can trigger a display refresh, a recalculation, a revalidation, or a reconstruction of the dependencies.

Deferred updates occur only through the action container element. It can be thought of as a switch that temporarily turns off the expensive processing, handles the child elements, and then catches up on any processing that still needs to be done. In this way, for instance, a series of insert actions, when placed inside an action element, wouldn't require a full recalculation for each insert just one to ensure consistency at the end.

Deferred updates apply to insert, delete, and setvalue.

Because of the way the XML Events defaulting works, placing ev:event attributes on XForms Action elements inside action will have no effect. Instead, the attribute should be placed on the action element itself the XForms Actions as child elements will still run within the context of the action.



XForms Essentials
Xforms Essentials
ISBN: 0596003692
EAN: 2147483647
Year: 2005
Pages: 117
Authors: Micah Dubinko

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net