Search code examples
orbeon

xf:dispatch action does not work on library component control


[form-builder]

Ok, so this has become two questions due to a problem trying to get some example code to work.

I have a form that has an action on a Password control that is hooked onto the password-check event to run some custom actions and submissions that event is dispatched to that control. The form builder submit button has been configured with custom actions, one of which is to dispatch the password-check event to the Password control. This all works.

As there is a need to create multiple forms with this same Password control on them, I want to move the section containing the Password control and its associated actions and submissions to a section library. I have moved the section to the section library for the application and rebuilt the form using the section template.

The published form includes the required submissions and actions as expected, but the dispatched event does not reach the Password control (in the debug logs, I can see the custom actions running and the event being dispatched, but it doesn't find(?) the control (see below):

2016-03-15 12:07:10,439 DEBUG XFormsServer  -   process: combining with then {action: "ActionNode(xf:dispatch,Map(Some(name) -> password-check, Some(targetid) -> Password-control))"}
2016-03-15 12:07:10,439 DEBUG XFormsServer  -   start process: running action {action: "ActionNode(xf:dispatch,Map(Some(name) -> password-check, Some(targetid) -> Password-control))"}
2016-03-15 12:07:10,439 DEBUG XFormsServer  -   end process: running action {time (ms): "0", result: "success"}

(as opposed to below):

2016-03-15 12:09:26,385 DEBUG XFormsServer  -   start process: running action {action: "ActionNode(xf:dispatch,Map(Some(name) -> password-check, Some(targetid) -> Password-control))"}
2016-03-15 12:09:26,386 DEBUG XFormsServer  -           start dispatching {name: "password-check", target: "SignOff-control≡xf-637≡Password-control"}
2016-03-15 12:09:26,386 DEBUG XFormsServer  -             start handler {name: "password-check", phase: "target", observer: "SignOff-control≡xf-637≡Password-control"}
2016-03-15 12:09:26,386 DEBUG XFormsServer  -               interpreter - start executing {action name: "xf:action"}
2016-03-15 12:09:26,386 DEBUG XFormsServer  -                 interpreter - start executing {action name: "xxf:script"}

To include some source code in this question, I created a form and library with just the Password control (and a test button), but noticed that the actions aren't being included in the published form (form1).

So the main question is how do I get the event to be dispatched to the Password control if the Password control is in an included section from a library?

The sub question is why weren't actions included in the published version of form1? I saw "Actions involving controls in a given section are automatically included with the section template, along with the services called by the actions.", which I thought would have been the case with the example code below.

properties-local.xml

<property as="xs:string" name="oxf.fr.detail.buttons.TEST.*">
  cancel
  submit
</property>

<property as="xs:string" name="oxf.fr.detail.process.submit.TEST.*">
  xf:dispatch(name = "password-validate", targetid = "field-control")
  then require-valid
  then xf:send("StoreDocument-submission")
</property>

TEST/library

<xh:html xmlns:xh="http://www.w3.org/1999/xhtml"
         xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
         xmlns:ev="http://www.w3.org/2001/xml-events"
         xmlns:xi="http://www.w3.org/2001/XInclude"
         xmlns:saxon="http://saxon.sf.net/"
         xmlns:xs="http://www.w3.org/2001/XMLSchema"
         xmlns:fb="http://orbeon.org/oxf/xml/form-builder"
         xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
         xmlns:sql="http://orbeon.org/oxf/xml/sql"
         xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
         xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
         xmlns:xf="http://www.w3.org/2002/xforms"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:exf="http://www.exforms.org/exf/1-0">
    <xh:head>
        <xh:title>Test Library</xh:title>
        <xf:model id="fr-form-model" xxf:expose-xpath-types="true">

            <!-- Main instance -->
            <xf:instance id="fr-form-instance" xxf:exclude-result-prefixes="#all">
                <form>
                    <Section>
                        <field/>
                        <button/>
                    </Section>
                </form>
            </xf:instance>

            <!-- Bindings -->
            <xf:bind id="fr-form-binds" ref="instance('fr-form-instance')">
                <xf:bind id="Section-bind" name="Section" ref="Section">
                    <xf:bind id="field-bind" name="field" ref="field"/>
                    <xf:bind id="button-bind" ref="button" name="button"/>
                </xf:bind>
            </xf:bind>

            <!-- Metadata -->
            <xf:instance xxf:readonly="true" id="fr-form-metadata" xxf:exclude-result-prefixes="#all">
                <metadata>
                    <application-name>TEST</application-name>
                    <form-name>library</form-name>
                    <title xml:lang="en">Test Library</title>
                    <description xml:lang="en"/>
                    <singleton>false</singleton>
                </metadata>
            </xf:instance>

            <!-- Attachments -->
            <xf:instance id="fr-form-attachments" xxf:exclude-result-prefixes="#all">
                <attachments>
                    <css mediatype="text/css" filename="" size=""/>
                    <pdf mediatype="application/pdf" filename="" size=""/>
                </attachments>
            </xf:instance>

            <!-- All form resources -->
            <!-- Don't make readonly by default in case a service modifies the resources -->
            <xf:instance id="fr-form-resources" xxf:readonly="false" xxf:exclude-result-prefixes="#all">
                <resources>
                    <resource xml:lang="en">
                        <Section>
                            <label>Section</label>
                        </Section>
                        <field>
                            <label/>
                            <hint/>
                        </field>
                        <button>
                            <label>Button</label>
                            <hint/>
                        </button>
                    </resource>
                </resources>
            </xf:instance>

            <!-- Utility instances for services -->
            <xf:instance id="fr-service-request-instance" xxf:exclude-result-prefixes="#all">
                <request/>
            </xf:instance>
            <xf:instance id="fr-service-response-instance" xxf:exclude-result-prefixes="#all">
                <response/>
            </xf:instance>
            <xf:action id="field-revalidate" ev:event="password-check" ev:observer="field-control">
                <xxf:script>
                    console.log('running revalidate');
                </xxf:script>
            </xf:action>
            <xf:action id="button-action" ev:event="DOMActivate" ev:observer="button-control">
                <xf:dispatch name="password-check" targetid="field-control"/>
            </xf:action>
        </xf:model>
    </xh:head>
    <xh:body>
        <fr:view>
            <fr:body xmlns:xbl="http://www.w3.org/ns/xbl"
                     xmlns:oxf="http://www.orbeon.com/oxf/processors"
                     xmlns:p="http://www.orbeon.com/oxf/pipeline">
                <fr:section id="Section-control" bind="Section-bind">
                    <xf:label ref="$form-resources/Section/label"/>
                    <fr:grid>
                        <xh:tr>
                            <xh:td>
                                <xf:input id="field-control" bind="field-bind">
                                    <xf:label ref="$form-resources/field/label"/>
                                    <xf:hint ref="$form-resources/field/hint"/>
                                    <xf:alert ref="$fr-resources/detail/labels/alert"/>
                                </xf:input>
                            </xh:td>
                            <xh:td>
                                <xf:trigger id="button-control" bind="button-bind">
                                    <xf:label ref="$form-resources/button/label"/>
                                    <xf:hint ref="$form-resources/button/hint"/>
                                    <xf:alert ref="$fr-resources/detail/labels/alert"/>
                                </xf:trigger>
                            </xh:td>
                        </xh:tr>
                    </fr:grid>
                </fr:section>
            </fr:body>
        </fr:view>
    </xh:body>
</xh:html>

TEST/form1

<xh:html xmlns:xh="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms"
         xmlns:xs="http://www.w3.org/2001/XMLSchema"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:ev="http://www.w3.org/2001/xml-events"
         xmlns:xi="http://www.w3.org/2001/XInclude"
         xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
         xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
         xmlns:exf="http://www.exforms.org/exf/1-0"
         xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
         xmlns:saxon="http://saxon.sf.net/"
         xmlns:sql="http://orbeon.org/oxf/xml/sql"
         xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
         xmlns:fb="http://orbeon.org/oxf/xml/form-builder">
    <xh:head>
        <xh:title>Form 1</xh:title>
        <xf:model id="fr-form-model" xxf:expose-xpath-types="true">

            <!-- Main instance -->
            <xf:instance id="fr-form-instance" xxf:exclude-result-prefixes="#all">
                <form>
                    <Section>
                        <field/>
                        <button/>
                    </Section>
                </form>
            </xf:instance>

            <!-- Bindings -->
            <xf:bind id="fr-form-binds" ref="instance('fr-form-instance')">
                <xf:bind id="Section-bind" ref="Section" name="Section"/>
            </xf:bind>

            <!-- Metadata -->
            <xf:instance xxf:readonly="true" id="fr-form-metadata" xxf:exclude-result-prefixes="#all">
                <metadata>
                    <application-name>TEST</application-name>
                    <form-name>form1</form-name>
                    <title xml:lang="en">Untitled Form</title>
                    <description xml:lang="en"/>
                    <singleton>false</singleton>
                </metadata>
            </xf:instance>

            <!-- Attachments -->
            <xf:instance id="fr-form-attachments" xxf:exclude-result-prefixes="#all">
                <attachments>
                    <css mediatype="text/css" filename="" size=""/>
                    <pdf mediatype="application/pdf" filename="" size=""/>
                </attachments>
            </xf:instance>

            <!-- All form resources -->
            <!-- Don't make readonly by default in case a service modifies the resources -->
            <xf:instance id="fr-form-resources" xxf:readonly="false" xxf:exclude-result-prefixes="#all">
                <resources>
                    <resource xml:lang="en">
                        <Section>
                            <label>Section</label>
                            <help/>
                        </Section>

                    </resource>
                </resources>
            </xf:instance>

            <!-- Utility instances for services -->
            <xf:instance id="fr-service-request-instance" xxf:exclude-result-prefixes="#all">
                <request/>
            </xf:instance>

            <xf:instance id="fr-service-response-instance" xxf:exclude-result-prefixes="#all">
                <response/>
            </xf:instance>

        </xf:model>
    </xh:head>
    <xh:body>
        <fr:view>
            <fr:body xmlns:xbl="http://www.w3.org/ns/xbl"
                     xmlns:oxf="http://www.orbeon.com/oxf/processors"
                     xmlns:p="http://www.orbeon.com/oxf/pipeline">
                <fr:section id="Section-control" bind="Section-bind">
                    <xf:label ref="$form-resources/Section/label"/>
                    <component:Section xmlns:component="http://orbeon.org/oxf/xml/form-builder/component/TEST/library"
                                       xmlns="http://orbeon.org/oxf/xml/form-builder"
                                       xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
                                       xmlns:fbf="java:org.orbeon.oxf.fb.FormBuilder"/>
                </fr:section>
            </fr:body>
        </fr:view>
    </xh:body>
</xh:html>

Solution

  • You can't target a control inside a section template with an xf:dispatch(), as controls within section templates are "insulated" from the "outside world" using XBL. (Consider that you could have multiple instance of a section template in a form, which means that you can't use the control names you picked when creating the section template to refer to those controls in the form.)

    We could imagine some version of xf:dispatch() that could target controls inside a section template, but it would need to also take the name of that section template as a parameter. As things stand, here is a workaround you could use:

    1. In your section template, add an output control, and hide it using CSS. Set its initial value to, say, 1.
    2. Instead of using xf:dispatch(), use xf:setvalue() and increment the value of the field by 1.
    3. When you get an xforms-value-changed on the output field, dispatch the password-check event. That will work since it is done from within the section template.