xmlcheckboxxformsexist-dbxsltforms

Adding checkbox to XForms repeat structure


I'm using XSLTForms in eXist 2.2 with the RESTXQ server.

I have a search form that lets users query a remote API, which responds with a set of XML records if the query is matched. I am using xf:repeat to iterate over the records, and I want to be able to provide a checkbox at the head of each record, so that the user can choose the records they want. However, when I place a checkbox element inside xf:repeat (using xf:input bound to a boolean value), I don't get the desired functionality. Instead of being independent of each other, the checkboxes get activated as a group. When I click the first box, the second box is activated as well, etc. This seems as though it would be a common enough use case, but I can't seem to find any documentation or examples showing how to implement it.

I know I need to sync the two instances somehow, to ensure that there is a new bool element for each checkbox, and I have tried different approaches with xf:insert, but I can't get anything to work.

Model snippet:

<xf:instance xmlns="" id="default">
    <results>            
        <sru:record sru:test="false">
            <sru:recordData>
                <marc:record>
                ...
                </marc:record>
            </sru:recordData>
        </sru:record>
        <sru:record sru:test="false">
            <sru:recordData>
                <marc:record>
                ...
                </marc:record>
            </sru:recordData>
        </sru:record>                
    </results>
</xf:instance>

<xf:bind nodeset="instance('default')/sru:record/@sru:test" id="checkVal" type="xs:boolean"/>

Form snippet with xf:repeat:

<div>
    <xf:repeat 
    nodeset="instance('default')/sru:record/sru:recordData/marc:record" 
    id="marc-repeat" appearance="full">
        <div class="checkbox">
            <xf:input incremental="true" ref="../../@sru:test">
                <xf:label>Select</xf:label>      
                <xf:action ev:event="DOMActivate">                                    
                    <xf:setvalue 
                    bind="checkVal" 
                    if=". = boolean-from-string('false')">true</xf:setvalue>
                    <xf:setvalue 
                    bind="checkVal" 
                    if=". = boolean-from-string('true')">false</xf:setvalue>    
                </xf:action>                           
            </xf:input>
        </div>
        ...
    </xf:repeat>
</div>

Solution

  • I finally figured out that I just needed a nested xf:repeat to iterate through the set of records. I think my problem stemmed from a confusion about the functionality of the xf:bind element, which I ended up removing. With this revised form structure, the value of each @sru:test attributes now updates independently.

    Form snippet with xf:repeat:

    <div>
        <xf:repeat 
        nodeset="instance('default')/sru:record/sru:recordData" 
        id="marc-repeat" appearance="full">
            <div class="checkbox">
                <xf:repeat nodeset="marc:record">
                    <xf:input incremental="true" ref="../../@sru:test">
                        <xf:label>Select</xf:label>      
                        <xf:action ev:event="DOMActivate">                                    
                            <xf:setvalue 
                            bind="checkVal" 
                            if=". = boolean-from-string('false')">true</xf:setvalue>
                            <xf:setvalue 
                            bind="checkVal" 
                            if=". = boolean-from-string('true')">false</xf:setvalue>    
                        </xf:action>                           
                    </xf:input>
                </div>
                ...
        </xf:repeat>
    </div>