Activate xforms button when instance is valid, inactivate otherwise

269 views Asked by At

I have an xforms instance that I have a number of binds set up for so I can warn a user about input errors.

When he is done he needs to be able to submit the data from the instance. I would like to toggle 'active' on the button depending on whether or not the instance is valid.

What's the best way to 'attack' this problem? I'm currently using a group around the button that basically repeats what the model bindings already said which feels redundant and is error prone because of out of sync logic.

Also: this instance has 3 bindings, but I have others with 30-40 bindings.

Current code:

<xforms:group ref=".[instance('new-terminology-association')[matches(@code,'^\S+$')][matches(@codeSystem,'^[0-2](\.(0|[1-9][0-9]*))*$')][string-length(@displayName)&gt;0]]">
    <fr:button>
        <xforms:label ref="$resources/create-association"/>
        <xforms:action ev:event="DOMActivate">
            ...
        </xforms:action>
    </fr:button>
</xforms:group>
2

There are 2 answers

3
avernet On

You could use the xxf:valid() function, pointing to the nodes you want to be valid. You can also point that function to a "parent" node, and ask it to check everything "under" that node is valid.

I think that function does what you're looking for, but because field values are only sent when users stab out of the field, this can create a somewhat unexpected user experience. For instance, imagine that the last field of your form, showing just before your button, is required. The user focuses on that field, and types a value. At this point the button is still disabled, since the value hasn't been sent to the server yet. Now the user hits tab, the value is sent to the server, the button would become enabled when the Ajax responses received, but since the button wasn't enabled at the time tab was pressed, the focus goes on something other than the button, which is somewhat unexpected. So, this is something to keep in mind.

0
Alexander Henket On

There is absolutely no way in Orbeon 4.7 to make the button/trigger respond directly to xxf:valid. This looks like a bug to me. Workaround code: add observer for xxforms-valid and xxforms-invalid that set true|false in a new instance. Add readonly binding based on ".='false'" for that instance and use ref="instance" on the trigger. On a busy form with lots of buttons that is a bit of a waste, but it'll have to make due. Thanks for you help, appreciated!

<xf:instance id="button-control">
    <button btn-term-add="false"/>
</xf:instance>
<xf:action ev:event="xxforms-invalid" ev:observer="new-terminology-association">
    <xf:setvalue ref="instance('button-control')/@btn-term-add" >false</xf:setvalue>
</xf:action>
<xf:action ev:event="xxforms-valid" ev:observer="new-terminology-association">
    <xf:setvalue ref="instance('button-control')/@btn-term-add">true</xf:setvalue>
</xf:action>
<xf:bind nodeset="instance('button-control')">
    <xf:bind ref="@btn-term-add" readonly=".='false'"/>
</xf:bind>

....

<xf:trigger ref="instance('button-control')/@btn-term-add">
    ....
</xf:trigger>