XForms JavaScript API
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 reuse. A JavaScript client-side API is provided to handle those cases, or other use cases involving JavaScript.
Calling JavaScript from XForms
Scripting actions
See Scripting Actions.
The javascript: protocol
[DEPRECATED SINCE Orbeon Forms 2016.1]
In addition to <xxf:script>
/ <xf:action>
, you can also use the javascript:
protocol from the <xf:load>
action to run scripts:
Using AVTs on the resource
attribute allows you to pass parameters from XForms to JavaScript, although you have to be careful to properly escape values.
Starting Orbeon Forms 2016.1, the recommended way to pass parameters is to use the nested <xxf:param>
attribute of scripting actions.
Calling XForms from JavaScript
Public API
The following objects are publicly exposed:
ORBEON.xforms.Document
ORBEON.xforms.Events.orbeonLoadedEvent
ORBEON.xforms.Events.errorEvent
Associated functions are described in more details below.
In addition, ORBEON.jQuery
exposes the version of jQuery used by Orbeon Forms.
Getting and setting controls value
controlIdOrElement
Yes
String
or HTMLElement
Either the id of the control without namespace (in the case of portal or embedding), or the control element.
newValue
Yes
Any value convertible with toString()
Value to set on the control (for setValue()
only).
form
No
HTMLElement
[SINCE Orbeon Forms 2016.1] The form object that corresponds to the XForms control you want to deal with. This argument is only needed when you have multiple "XForms forms" on the same HTML page, which only happens if you are running your form in embedded mode and you have multiple forms 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.
To get a control value, use:
var value = ORBEON.xforms.Document.getValue(myControl)
.To set a 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 thexforms-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.
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.
The input control below is bound to <foo>
, and the output control is bound to <bar>
. When activated, the trigger executes JavaScript with the <xxf: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>
.
For forms created in Form Builder
Keep in mind that, in Form Builder, if you have a field named first-name
, the XForms id for that field will be first-name-control
. Also, because your field is inside other containers, for instance a section, the id in the HTML for that field will have some prefix. Consequently, when using getValue()
and setValue()
described above, you'll want to write code along those lines:
The first line above uses the $=
CSS selector to get the element in the DOM whose id ends with first-name-control
.
For compound XBL controls
Some XBL controls, like <fr:dropdown>
AKA <xf:select1 appearance="dropdown">
are compound controls: they are built out of other controls and do not directly export a value to JavaScript.
For those, you have to go search for the nested core XForms control which holds the value, in this case the .xforms-select1
control:
Setting focus on a control
[SINCE Orbeon Forms 2017.2]
This function sets keyboard focus on the given control and lets the server know about the focus change if needed.
controlIdOrElement
Yes
String
or HTMLElement
Either the id of the control without namespace (in the case of portal or embedding), or the control element.
form
No
HTMLElement
The form object that corresponds to the XForms control you want to deal with. This argument is only needed when you have multiple "XForms forms" on the same HTML page, which only happens if you are running your form in embedded mode and you have multiple forms 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.
Example:
Actual focus only takes place if the control is focusable, not readonly, and not hidden within a hidden switch
/case
or dialog
.
Dispatching events
Basic usage
You can dispatch your own events from JavaScript by calling the function ORBEON.xforms.Document.dispatchEvent()
. The function takes a single parameter which is an object with properties as defined in the table below. Calling the function with several parameters in order listed in the table below is supported as a deprecated alternative for backward compatibility.
In most cases, you only need to call dispatchEvent()
with a target id and event name, as in:
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 explicitly declared to handle the do-something
event on the XForms model:
Parameters
targetId
Yes
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 <xf:model>
, <xf:instance>
, or <xf:submission>
.
eventName
Yes
Name of the event.
properties
No
Allows you to attach custom properties to the event.
form
No
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, which only happens if you are running your form in embedded mode and you have multiple forms 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.
incremental
No
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
No
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
.
The following parameters were previously documented but had no effect. They are ignored and you should not use them:
bubbles
cancelable
Security considerations
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 xxf:external-events
attribute on the first <xf:model>
element, for example:
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.
XBL components can also declare that they support external events:
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.
Any XForms control can declare external events with the xxf:external-events
attribute:
Custom properties
The properties
parameter is a JSON object:
For instance:
When properties are provided, the code handling the event can access the property values with the event()
function. With the event dispatched above, in the handler for my-event
on my-target
, calling event('p1')
will return the string 'v1'
.
Passing properties is only supported when calling dispatchEvent()
with a single object parameter; it isn't supported when calling it with multiple parameters.
The orbeonLoaded event
The ORBEON.xforms.Events.orbeonLoadedEvent
fires when the form is fully loaded and initialized.
To add your event listener on, say orbeonLoadedEvent
, write:
The above does a few things:
Add an event listener upon
DOMContentLoaded
(similar to jQuery's "ready"). When this event fires, the globalORBEON
object exists.Add your event handler for "orbeonLoaded".
NOTE: In some cases, if the Orbeon Forms initialization happened before adding the event handler, it was possible that the event could not fire. This is fixed with issue #3891.
The error event
The ORBEON.xforms.Events.errorEvent
fires when the JavaScript code catches an error.
See also JavaScript event handler.
The arguments of the listener for errorEvent
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).
Removing event listeners
To remove your event listener on, say orbeonLoadedEvent
, you'll need to implement your listener in a named function, say myListener
:
See also
Last updated