Rationale
While XForms gets you a long way towards creating a dynamic
user-friendly user interface, there are some dynamic behaviors of the
user interface that cannot be implemented easily or at all with XForms,
or you might already have some JavaScript code that you would like to
reused. A JavaScript API is provided to handle those cases, or other use
cases involving JavaScript.
Calling JavaScript from XFormsThe <xxforms:script> action
See Actions - <script> action. The javascript: protocol[SINCE 2012-05-22] In addition to <xxforms:script> / <xforms:action>, you can also use the javascript: protocol from the <xforms:load> action to run scripts: <xforms:load resource="javascript:ORBEON.Builder.controlAdded.fire('{$effective-id}')"/>
Using AVTs on the resource attribute, this allows you to pass parameters from XForms to JavaScript. Calling XForms from JavaScript
Getting and Setting Controls Value
ORBEON.xforms.Document.getValue(controlIdOrElement)
ORBEON.xforms.Document.setValue(controlIdOrElement, value)
To:
- Get a control value, use:
var value =
ORBEON.xforms.Document.getValue(myControl).
- Set control value, use:
ORBEON.xforms.Document.setValue(myControl, "42"). Setting the
value with JavaScript is equivalent to changing the value of the control
in the browser. This will trigger the recalculation of the instances,
and the dispatch of the xforms-value-changed event. More formally, the
Value Change sequence of events occurs.
For both getValue() and setValue():
- The first parameter (
myControl in the above example) can either be:
- The id of the control (a string).
- The element in the DOM that has this id.
- Within repeats, currently you have to pass an "effective id", which is
the id as found within the HTML element. Effective ids usually have the
form
myControl·1-2,
where the suffix indicates the levels of repetition. The "·" character is unicode U+00B7.
As an example, consider you have the model below. It declares an
instance with two elements <foo> and <bar>, where <bar> is a copy of <foo>,
implemented with a calculate MIP.
<xforms:model>
<xforms:instance id="instance">
<instance>
<foo>42</foo>
<bar/>
</instance>
</xforms:instance>
<xforms:bind
nodeset="/instance/bar" calculate="/instance/foo"/>
</xforms:model>
The input control below is bound to <foo>, and the output control is bound to <bar>. When
activated, the trigger executes JavaScript with the <xxforms:script>
action. It increments the value of the input control bound to <foo>. When
this happens the value displayed by the output control bound to <bar> is
incremented as well, as <bar> is a copy of <foo>.
<xhtml:p>
<xforms:input
ref="foo" id="foo">
<xforms:label class="fixed-width">Value of
foo:</xforms:label>
</xforms:input>
</xhtml:p>
<xhtml:p>
<xforms:output
ref="bar">
<xforms:label class="fixed-width">Value of
bar:</xforms:label>
</xforms:output>
</xhtml:p>
<xhtml:p>
<xforms:trigger>
<xforms:label>Increment foo with JavaScript</xforms:label>
<xxforms:script ev:event="DOMActivate">
var fooValue = ORBEON.xforms.Document.getValue("foo");
ORBEON.xforms.Document.setValue("foo", Number(fooValue) + 1);
</xxforms:script>
</xforms:trigger>
</xhtml:p>
Dispatching Events
ORBEON.xforms.Document.dispatchEvent()
You can dispatch your own events from JavaScript by calling the function
ORBEON.xforms.Document.dispatchEvent().
The parameters to this function are:
| targetId |
Mandatory |
Id of the target element. The
element must be an element in the XForms
namespace: you cannot dispatch events to HTML elements. In addition,
the id must identify either a relevant and non-readonly XForms control,
or a model object that supports event handlers such as
<xforms:model>,
<xforms:instance>,
or
<xforms:submission>. |
| eventName |
Mandatory |
Name of the event.
Note:
For security reasons, by default Orbeon Forms prohibits client-side
JavaScript from dispatching any external events except DOMActivate,
DOMFocusIn, DOMFocusOut, and keypress. Furthermore, these events can only be
dispatched to relevant and non-readonly XForms controls. In order to
enable dispatching of custom events, you must first add the
xxforms:external-events
attribute on the first <xforms:model>
element, for example:
<xforms:model xxforms:external-events=
"acme-super-event acme-famous-event">
...
</xforms:model>
This attribute contains a space-separated list of event name. In this
example, you explicitly enable your JavaScript code to fire the two
events acme-super-event
and acme-famous-event
to any relevant and
non-readonly XForms controls, or to any model object supporting event
handlers. Note that you can only enable custom events, but you cannot
enable standard XForms or DOM events in addition to DOMActivate,
DOMFocusIn and DOMFocusOut.
Since the event handlers for custom events can be called by JavaScript
code that runs on the client, you need to be aware that these handlers
can potentially be activated by anybody able to load the form in his
browser.
[SINCE 2012-04-09] XBL components can also declare that they support external events:
<xbl:binding xxforms:external-events=
"acme-super-event acme-famous-event">
<xbl:handlers>
<xbl:handler event="acme-super-event" phase="target">
...
</xbl:handler>
</xbl:handlers
...
</xbl:binding>
In that case the setting is only valid for the given XBL binding, not for the entire form. This in particular allows JavaScript companion code to communicate with XBL components.
|
| form |
Optional |
The form object that corresponds
to the XForms form you want to
dispatch the event to. This argument is only needed when you have
multiple "XForms forms" on the same HTML page. Typically, this would
only happens if you are running your form in a portal and you have
multiple portlets using XForms on the same page. When the parameter is
not present or null, the first form on the HTML page with the class
xforms-form is
used. |
| bubbles |
Optional |
Optional boolean indicating if
this event bubbles, as defined in DOM2
Events. The default value depends on the definition of the custom event. |
| cancelable |
Optional |
Optional boolean indicating if
this event is cancelable, as defined in DOM2
Events. The default value depends on the definition of the custom event. |
| incremental |
Optional |
When false the event is sent to the XForms server right away. When
true
the event is sent after a small delay, giving the opportunity for other
events that would occur during that time span to be aggregated with the
current event.
|
| ignoreErrors |
Optional |
When set to true, errors happening while the event is dispatched to
the
server are ignored. This is in particular useful when you are using a
JavaScript timer (e.g. window.setInterval())
that runs a JavaScript
function on a regular interval to dispatch an event to the server,
maybe to have part of the UI updated. In some cases, you might not want
to alert the user when a there is a maybe temporary communication error
while the event is being dispatched to the server. In those cases, you
call dispatchEvent()
with ignoreErrors
set to true. |
In most cases, you only need to call dispatchEvent() with a target id and event name,
as in:
ORBEON.xforms.Document.dispatchEvent("main-model",
"do-something");
An event handler for the custom event can be in an XForms model or
control, and can execute any valid XForms action. Here an action is
explicatly declared to handle the do-something event on the XForms model:
<xforms:model id="main-model"
xxforms:external-events="do-something">
<xforms:action
ev:event="do-something">
<xforms:setvalue ref="first-name"
value="instance('default-values')/first-name"/>
<xforms:toggle case="first-name-case"/>
</xforms:action>
</xforms:model>
Custom Events
You can listen in your code on the
following events:
ORBEON.xforms.Events.orbeonLoadedEvent –
Fired when the form is fully loaded and initialized.
ORBEON.xforms.Events.errorEvent – Fired
when the JavaScript code catches an error. By default a dialog is shown
to the user when an error is intercepted. If you prefer to show your
own dialog or to implement some other behavior in case of error, most
likely you will want to:
- Disable the default error dialog by
setting the
oxf.xforms.show-error-dialog
property to false.
- Register your own listener on
ORBEON.xforms.Events.errorEvent.
To
register (subscribe) your event listener on, say orbeonLoadedEvent,
write:
ORBEON.xforms.Events.orbeonLoadedEvent.subscribe(function(eventName,
eventData) {
// Code of your listener
});
The
arguments of your listener are as follows:
- The first
argument is the name of the event (the string
errorEvent),
which most likely you don't need to know about if that listener is
explicitly registered to this event.
- The second argument
contains information about the error. Assuming you defined your second
argument to be named
eventData, inside your listener you
can access:
eventData.title – A string
describing the issue.
eventData.details – A
string containing HTML with more information about the error, including:
- If
it happened in JavaScript: information of where the error happened
(such as the file name and the line number).
- If if happened on
the server: detailed information about where the error happened (such as
the invalid XPath expression and the file where that expression is
found).
To unregister (unsubscribe) you
event listener on, say orbeonLoadedEvent, you'll need to
implement your listener in a named function, say myListener:
ORBEON.xforms.Events.orbeonLoadedEvent.unsubscribe(myListener);
|