Managing repeatable sections through events with orbeon

226 views Asked by At

I found a few questions related to my problem (Orbeon index of repeat in repeatable section, Orbeon relevant properties and Orbeon nested repeats), but I couldn't get any of them to work properly.
I define a repeatable section with a couple of questions inside and a some relevant rules. I also define some events to manage the visibility of the questions. The problem appears when I create several repeated groups. When I select one of the answers, the relevant rules and the events are launched for all the questions with the same xpath route.
So, my question is: Is there a way to manage the same events ans the same relevant rules for repeatable sections?. That is, could I define some kind of dynamic route based on the index of the section that the user is selecting at the moment and use it in the relevant rules and the events?

The complete code used for the example is below:

    <xh:html xmlns:xh="http://www.w3.org/1999/xhtml"
     xmlns:ev="http://www.w3.org/2001/xml-events"
     xmlns:exf="http://www.exforms.org/exf/1-0"
     xmlns:fb="http://orbeon.org/oxf/xml/form-builder"
     xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
     xmlns:saxon="http://saxon.sf.net/"
     xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
     xmlns:sql="http://orbeon.org/oxf/xml/sql"
     xmlns:xf="http://www.w3.org/2002/xforms"
     xmlns:xi="http://www.w3.org/2001/XInclude"
     xmlns:xs="http://www.w3.org/2001/XMLSchema"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
     xmlns:xxi="http://orbeon.org/oxf/xml/xinclude">
    <xh:head>
    <xh:meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
    <xh:title>Test_repeatable</xh:title>
    <xf:model id="fr-form-model" xxf:expose-xpath-types="true">
        <xf:instance xxf:readonly="true" id="fr-form-metadata" xxf:exclude-result-prefixes="#all">
            <metadata>
                <application-name>Test_app</application-name>
                <form-name>Test_repeatable_v1</form-name>
                <title xml:lang="en">Test_repeatable</title>
                <description xml:lang="en">Description of the form.</description>
                <singleton>false</singleton>
            </metadata>
        </xf:instance> 
        <xf:instance id="fr-form-instance">
            <form>
                <Category>
                    <Group>
                        <Group-iterator>
                            <Question/>
                            <Question2/>
                            <Question3/>
                        </Group-iterator>
                    </Group>
                </Category>
            </form>
        </xf:instance>
        <xf:bind id="fr-form-binds" ref="instance('fr-form-instance')">
            <xf:bind id="Category-bind" name="Category" ref="/form/Category">
                <xf:bind id="Group-bind" name="Group" ref="/form/Category/Group">
                    <xf:bind id="Group-iterator-bind" name="Group-iterator"
                             ref="/form/Category/Group/Group-iterator">    
                        <xf:bind id="Question-bind" name="Question" ref="Question" required="true()"/>
                        <xf:bind id="Question2-bind"
                                 name="Question2"
                                 readonly="false"
                                 ref="Question2"
                                 relevant="/form/Category/Group/Group-iterator/Question='Answer'"
                                 required="true()"/>

                        <xf:bind id="Question3-bind"
                                 name="Question3"
                                 readonly="false"
                                 ref="Question3"
                                 relevant="/form/Category/Group/Group-iterator/Question='Answer2' or instance('visible')/Group/Group-iterator/Question2 != 'false' "
                                 required="true()"/>
                    </xf:bind>
                </xf:bind>
            </xf:bind> 
        </xf:bind>
        <xf:instance id="fr-form-attachments">
            <attachments>
                <css filename="" mediatype="text/css" size=""/>
                <pdf filename="" mediatype="application/pdf" size=""/>
            </attachments>
        </xf:instance>
        <xf:instance id="fr-form-resources" xxf:readonly="false">
            <resources>
                <resource xml:lang="en">
                    <Category>
                        <label>Category</label>
                        <hint/>
                        <alert/>
                        <Group>
                            <label>Group</label>
                            <hint/>
                            <alert/>
                            <Question>
                                <label>Question</label>
                                <hint/>
                                <alert/>
                                <item>
                                    <label>Answer</label>
                                    <hint/>
                                    <value>Answer</value>
                                </item>
                                <item>
                                    <label>Answer2</label>
                                    <hint/>
                                    <value>Answer2</value>
                                </item>
                            </Question>
                            <Question2>
                                <label>Question2</label>
                                <hint/>
                                <alert/>
                            </Question2>
                            <Question3>
                                <label>Question3</label>
                                <hint/>
                                <alert/>
                            </Question3>
                        </Group>
                    </Category>
                </resource>
            </resources>
        </xf:instance>
        <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:instance xxf:readonly="true" id="Group-template">
            <Group-iterator>
                <Question/>
                <Question2/>
                <Question3/>
            </Group-iterator>
        </xf:instance>
        <!-- Keep track of visible/hidden status -->
        <xf:instance id="visible">
            <visible>
                <Category>0</Category>
                <Group>
                    <Group-iterator>
                        <Question>false</Question>
                        <Question2>false</Question2>
                        <Question3>false</Question3>
                    </Group-iterator>
                </Group> 
            </visible>
        </xf:instance>

        <!-- Change the visibility status for 'Question'. -->
        <xf:setvalue ev:event="xforms-enabled" observer="Question-control"
                     ref="instance('visible')/Group/Group-iterator/Question"
                     value="'true'"/>
        <xf:setvalue ev:event="xforms-disabled" observer="Question-control"
                     ref="instance('visible')/Group/Group-iterator/Question"
                     value="'false'"/>
        <!-- Update category showed elements count for 'Question'. -->
        <xf:setvalue ev:event="xforms-enabled" observer="Question-control"
                     ref="instance('visible')/Category"
                     value="instance('visible')/Category + 1"/>
        <xf:setvalue ev:event="xforms-disabled" observer="Question-control"
                     ref="instance('visible')/Category"
                     value="instance('visible')/Category - 1"/>
        <!-- Change the visibility status for 'Question2'. -->
        <xf:setvalue ev:event="xforms-enabled" observer="Question2-control"
                     ref="instance('visible')/Group/Group-iterator/Question2"
                     value="'true'"/>
        <xf:setvalue ev:event="xforms-disabled" observer="Question2-control"
                     ref="instance('visible')/Group/Group-iterator/Question2"
                     value="'false'"/>
        <!-- Update category showed elements count for 'Question2'. -->
        <xf:setvalue ev:event="xforms-enabled" observer="Question2-control"
                     ref="instance('visible')/Category"
                     value="instance('visible')/Category + 1"/>
        <xf:setvalue ev:event="xforms-disabled" observer="Question2-control"
                     ref="instance('visible')/Category"
                     value="instance('visible')/Category - 1"/>
        <!-- Change the visibility status for 'Question3'. -->
        <xf:setvalue ev:event="xforms-enabled" observer="Question3-control"
                     ref="instance('visible')/Group/Group-iterator/Question3"
                     value="'true'"/>
        <xf:setvalue ev:event="xforms-disabled" observer="Question3-control"
                     ref="instance('visible')/Group/Group-iterator/Question3"
                     value="'false'"/>
        <!-- Update category showed elements count for 'Question3'. -->
        <xf:setvalue ev:event="xforms-enabled" observer="Question3-control"
                     ref="instance('visible')/Category"
                     value="instance('visible')/Category + 1"/>
        <xf:setvalue ev:event="xforms-disabled" observer="Question3-control"
                     ref="instance('visible')/Category"
                     value="instance('visible')/Category - 1"/>            
    </xf:model>
</xh:head>
<xh:body>
    <fr:view>
        <fr:body xmlns:oxf="http://www.orbeon.com/oxf/processors"
                 xmlns:p="http://www.orbeon.com/oxf/pipeline"
                 xmlns:xbl="http://www.w3.org/ns/xbl"
                 xmlns:dataModel="java:org.orbeon.oxf.fb.DataModel">        
                <fr:section bind="Category-bind"
                            id="Category-control">
                    <xf:label mediatype="text/html"
                              ref="instance('fr-form-resources')/resource/Category/label"/>
                    <xf:hint ref="instance('fr-form-resources')/resource/Category/hint"/>
                    <xf:alert ref="instance('fr-form-resources')/resource/Category/alert"/>
                    <fr:section bind="Group-bind"
                                id="Group-control"
                                max="100"
                                min="1"
                                repeat="content"
                                template="instance('Group-template')">    
                        <xf:label mediatype="text/html"
                                  ref="instance('fr-form-resources')/resource/Category/Group/label"/>
                        <xf:hint ref="instance('fr-form-resources')/resource/Category/Group/hint"/>
                        <xf:alert ref="instance('fr-form-resources')/resource/Category/Group/alert"/>
                        <xh:tr>
                            <xh:td>
                                <xf:select1 appearance="full" bind="Question-bind"
                                            id="Question-control">
                                    <xf:label mediatype="text/html"
                                              ref="instance('fr-form-resources')/resource/Category/Group/Question/label"/>
                                    <xf:hint ref="instance('fr-form-resources')/resource/Category/Group/Question/hint"/>
                                    <xf:alert ref="instance('fr-form-resources')/resource/Category/Group/Question/alert"/>
                                    <xf:itemset 
                                                ref="instance('fr-form-resources')/resource/Category/Group/Question/item">
                                        <xf:label ref="label"/>
                                        <xf:value ref="value"/>
                                        <xf:hint ref="hint"/>
                                    </xf:itemset>
                                </xf:select1>
                            </xh:td>
                        </xh:tr>
                        <xh:tr>
                            <xh:td>
                                <xf:input bind="Question2-bind"
                                          id="Question2-control">
                                    <xf:label mediatype="text/html"
                                              ref="instance('fr-form-resources')/resource/Category/Group/Question2/label"/>
                                    <xf:hint ref="instance('fr-form-resources')/resource/Category/Group/Question2/hint"/>
                                    <xf:alert ref="instance('fr-form-resources')/resource/Category/Group/Question2/alert"/>
                                </xf:input>
                            </xh:td>
                        </xh:tr>
                        <xh:tr>
                            <xh:td>
                                <xf:input bind="Question3-bind"
                                          id="Question3-control">
                                    <xf:label mediatype="text/html"
                                              ref="instance('fr-form-resources')/resource/Category/Group/Question3/label"/>
                                    <xf:hint ref="instance('fr-form-resources')/resource/Category/Group/Question3/hint"/>
                                    <xf:alert ref="instance('fr-form-resources')/resource/Category/Group/Question3/alert"/>
                                </xf:input>
                            </xh:td>
                        </xh:tr>
                    </fr:section>
                </fr:section>
        </fr:body>
    </fr:view>
</xh:body>
</xh:html>

EDIT: A little explanation of the code above.
This example has two sections, one normal and inside of it one repeatable. Inside the repeatable section there are three questions. The first question has two answers. When I select the first answer the form runner must show the questions two and three. When the second answer is selected the runner must show only the third question. This works correctly if I only have one repeatable section.
The problem appears when I create a new repeatable section. If I select the answer one of the first question, the following questions are shown at the same time in both repeatable groups. The same when I select answer two.
So the question is: Is there a way to tell the Orbeon runner that it must apply the relevant rules only to the repeatable group where the event happens?

EDIT 2: Ok, your solution is working perfect in the case of 'Question2'. The problem comes with Question 3. If you check the code for Question3 you can see that I try to access also another instance:

relevant="$Question='Answer2' or instance('visible')/Group/Group-iterator/Question2 != 'false' "

The 'visible' instance is not related with any control or bind, is only used for storing an internal value for the questions and is updated using xforms events, as you can see in the code below:

<xf:setvalue ev:event="xforms-enabled" 
 observer="Question2-control" 
 ref="instance('visible')/Group/Group-iterator/Question2" 
 value="'true'"/>

Thus, my new question is: Is there a way to store different values for different iterations of a repeatable section in a static instance and accessing them using a dynamic path (like in your first response with the $)?

1

There are 1 answers

5
avernet On

If in the xf:bind for Question2 you want to refer to the value of Question in the same iteration, then just use $Question. In fact, as a rule of thumb, you can always refer to the value of another control gaga as $gaga, and trust that the right thing will happen. (At least it will in most cases.) So, your xf:bind for Question2 will become:

<xf:bind id="Question2-bind" name="Question2"
    readonly="false" ref="Question2"
    relevant="$Question='Answer'"
    required="true()"/>