JavaScript

Define a class for your component

The XBL component shipped with Orbeon Forms are stored in their own directory under /xbl/orbeon. For instance, all the files for the currency component are under /xbl/orbeon/currency. To include a JavaScript file, use the <xbl:script> element directly inside the <xbl:xbl>:

<xbl:xbl>
    <xbl:script src="/xbl/orbeon/currency/currency.js"/>
    <xbl:binding id="fr-currency" element="fr|currency">
        ....
    </xbl:binding>
</xbl:xbl>

In the JavaScript file corresponding to your component, declare a class as follows:

YAHOO.namespace("xbl.fr");
YAHOO.xbl.fr.Currency = function() {};
ORBEON.xforms.XBL.declareClass(YAHOO.xbl.fr.Currency, "xbl-fr-currency");
YAHOO.xbl.fr.Currency.prototype = {

    attribute1: null,
    attribute2: null,

    init: function() {
        ...
    },

    valueChanged: function() {
        ...
    },

    ...
};
  • YAHOO.namespace("xbl.fr") defines a namespace for your class. All the XBL components components that ship with Orbeon Forms are in the xbl.fr namespace. If you are defining a component for your company or project named Acme, you could use the namespace xbl.acme.

  • ORBEON.xforms.XBL.declareClass() defines your class as an XBL class:

    • It takes 2 parameters: your class, and the CSS class found on the most HTML element that contains the markup for your components. This element is generated by Orbeon Forms, and the class name is derived from the id of your <xbl:binding>; for instance, if the id is fr-currency, the class name is xbl-fr-currency.
    • It adds a static method to your class called instance(). It is a factory method, which you will use to get or create an object corresponding to the "current" component (more on this later). It define a static container attribute. In your JavaScript code, you can refer to this.container to retrieve the most outer HTML element corresponding to your component. For instance, if you know you have an input with the class xbl-fr-currency-xforms-input inside your component, you get the HTML element corresponding to that input with:
YAHOO.util.Dom.getElementsByClassName(
    "xbl-fr-currency-xforms-input",
    null,
    this.container
)[0];

Call methods of your class on XForms events

You can call a JavaScript method defined in your JavaScript class when an XForms event occurs. For instance, to call the init() method when on xforms-enabled, write:

<xxf:script ev:event="xforms-enabled">YAHOO.xbl.fr.Currency.instance(this).init();</xxf:script>

The instance() method acts as an object factory for your component: it returns an instance of your class corresponding to the "current" component. It creates an instance of your class as necessary, and keeps track of existing objects, maintaing a 1-to-1 mapping between instances of the XBL component in the form and instance of your JavaScript class.

Read-only parameters

So your JavaScript can access the current value of parameters and be notified when their value changes, include the oxf:/oxf/xslt/utils/xbl.xsl XSL file, and call xxbl:parameter() function for each parameter, as in:

<xbl:xbl>
    <xbl:script src="/xbl/orbeon/currency/currency.js"/>
    <xbl:binding id="fr-currency" element="fr|currency">
        <xbl:template xxbl:transform="oxf:unsafe-xslt">
            <xsl:transform version="2.0">
                <xsl:import href="oxf:/oxf/xslt/utils/xbl.xsl"/>
                <xsl:template match="/*">
                    ...
                    <xsl:copy-of select="xxbl:parameter(., 'prefix')"/>
                    <xsl:copy-of select="xxbl:parameter(., 'digits-after-decimal')"/>
                    ...
                </xsl:template>
            </xsl:transform>
        </xbl:template>
    </xbl:binding>
</xbl:xbl>

The arguments of xxbl:parameter() are:

  1. The element corresponding to your component, e.g. the <fr:currency> element written by the user of your component. If your template matches on /*, this will be the current node.
  2. The name of the parameter.

Then in JavaScript, you can access the current value of the property with:

var prefixElement =
    YAHOO.util.Dom.getElementsByClassName(
        "xbl-fr-currency-prefix",
        null,
        this.container
    )[0];

var prefix =
    ORBEON.xforms.Document.getValue(prefixElement.id);

Whenever the value of a parameter changes, a method of your JavaScript class is called. The name of this method is parameterFooChanged if "foo" is the name of your property. Parameters names are in lowercase and use dash as a word separator, while the method names use camel case. E.g. if your parameter name is digits-after-decimal, you will defined a method parameterDigitsAfterDecimalChanged.

Sending events from JavaScript

You can dispatch custom events to bindings from JavaScript using the ORBEON.xforms.Document.dispatchEvent() function. If you are calling it with custom events, make sure you are allowing the custom event names on the binding first:

<xbl:binding xxf:external-events="acme-super-event acme-famous-event">
    <xbl:handlers>
        <xbl:handler event="acme-super-event" phase="target">
            ...
        </xbl:handler>
    </xbl:handlers
    ...
</xbl:binding>