XForms bind does not update when referenced instance data is updated - orbeon

My problems is this:
I have 2 instances in my model:
<xf:instance id="Include-model">
<data>
<value type="xs:string">true</value>
</data>
</xf:instance>
this is wired up to a checkbox,
and
<xf:instance id="items-model">
<items>
<item>1</item>
<item>2</item>
<item>3</item>
</xf:instance>
and I have a bind declared as:
<xforms:bind id="items-bind" nodeset="items[instance('Include-model')/value = 'true']">
the checkbox correctly updates the Include-model, but the bind does not update to reflect this. Basically, if the checkbox is checked I need to display the items, otherwise hide them. The initial state is correct, but changes are not reflected in the bind when I check/uncheck the checkbox.
Eternal gratitude to all who can help.

You might try
<xforms:bind id="items-bind" nodeset="instance('items-model')" relevant="instance('Include-model')/value = 'true'" />

First up, I could see there are multiple issues in the code snippets you give here.
closing tag is missing here. It should look like
<xforms:instance id="items-model">
<items>
<item>1</item>
<item>2</item>
<item>3</item>
</items>
</xforms:instance>
The nodeset in the bind mentioned is for items. It should be for item. Since there is no information given whether it a code pulled from form-builder or "hand-written" code, i cannot say it is correct or not. For a "hand-written" codes the bind defnition in your case will look like this
<xforms:bind id="items-bind" nodeset="instance('items-model')/item[instance('Include-model')/value = 'true']" />
Below is the complete Xforms code you can run for this case. Try running with value as 'true' and again value as 'false' to understand how bind is working.
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
xmlns:xforms="http://www.w3.org/2002/xforms">
<xhtml:head>
<xhtml:title>Xforms</xhtml:title>
<xforms:model>
<xforms:instance id="Include-model">
<data>
<value type="xs:string">true</value>
</data>
</xforms:instance>
<xforms:instance id="items-model">
<items>
<item>1</item>
<item>2</item>
<item>3</item>
</items>
</xforms:instance>
<xforms:bind id="items-bind" nodeset="instance('items-model')/item[instance('Include-model')/value = 'true']" />
</xforms:model>
</xhtml:head>
<xhtml:body>
<table>
<tr>
<td>Bind items are
<xforms:output value="
string-join(xxforms:bind('items-bind'), ' -- ')
" />
</td>
</tr>
</table>
</xhtml:body>
</xhtml:html>

Related

How to make resource language attribute dynamic in Orbeon Forms?

In my model i define an instance related to form-resources.
I want to set "xml:lang" value dynamically by a xpath expr in a variable.
I tried but the xml:lang attribute of resource element isn't evaluating the variable, but instead it recognises it as string! (xml:lang="$language")
...
<xf:model id="fr-form-model" xxf:expose-xpath-types="true">
<xf:var name="language" value="de" as="xs:string" />
...
<xf:instance id="fr-form-resources" xxf:readonly="false">
<resources>
<!-- How "xml:lang" attribute can have dynamic value
from a variable/xpath instead of static string 'de' ? -->
<resource xml:lang="de">
<IntegerField>
<label>%translation.IntegerField%</label>
<IntegerField />
</Project>
<cancel>
<label>%translation.cancel%</label>
<hint />
</cancel>
<ok>
<label>%translation.ok%</label>
<hint />
</ok>
</resource>
</resources>
</xf:instance>
</xf:model>
Is there any way to achieve this?
Using Orbeon 4.5
Use an xf:bind for this; something like:
<xf:bind
ref="instance('fr-form-resources')/resource/#xml:lang"
calculate="$language"/>
This is the general mechanism in XForms to have something an instance automatically calculated and re-evaluated as users interact with the form.

How come that when inserting a new row in a repeat with a bind attribute the repeat index is not updated to the newly inserted row in orbeon xforms?

Our software generates XForms. For repeating structures it generates xf:repeat elements with a bind attribute referring to the binding model to determine its repeat collection. From the xforms specification we understand that the repeat index should always be updated to the last inserted row, but this is not what is happening. When using the ref or nodeset attribute for the repeat, the repeat index is updated as expected.
Small example to demonstrate this:
<?xml version="1.0" encoding="UTF-8"?>
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
xmlns:idc="http://www.inventivedesigners.com/xbl"
xmlns:exf="http://www.exforms.org/exf/1-0"
xmlns:saxon="http://saxon.sf.net/">
<xhtml:head>
<xhtml:meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<xhtml:title>Test</xhtml:title>
<xf:model id="m-default">
<xf:instance id="i-default">
<data xmlns="">
<repeat>
<id>1</id>
</repeat>
</data>
</xf:instance>
<xf:instance id="i-counter">
<form xmlns="">
<counter>1</counter>
</form>
</xf:instance>
<!-- bindings -->
<xf:bind nodeset="repeat" id="repeat-bind" />
</xf:model>
</xhtml:head>
<xhtml:body style="width: 80%; margin-left: auto; margin-right: auto;">
<xhtml:table style="border: 1px solid black; margin-top: 50px;">
<xhtml:tbody>
<xf:repeat id="my_repeat" bind="repeat-bind">
<xhtml:tr>
<xhtml:td>
<xf:output ref="id" />
</xhtml:td>
</xhtml:tr>
</xf:repeat>
</xhtml:tbody>
</xhtml:table>
<xf:trigger>
<xf:label>Insert</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue value="number(.) + 1" ref="instance('i-counter')/counter"/>
<xf:insert position="after" nodeset="repeat" at="index('my_repeat')"/>
<xf:setvalue value="instance('i-counter')/counter" ref="repeat[last()]/id"/>
</xf:action>
</xf:trigger>
<fr:xforms-inspector/>
</xhtml:body>
</xhtml:html>
If you press the button four times you will see that the order is 1,4,3,2 when we expect 1,2,3,4. When using the ref attribute on the repeat the output is as expected.
I tested this with Orbeon 4.4 and the latest 4.8 but the behaviour is the same. What is the reason for the difference between using bind and ref?
I updated the github issue with an explanation of why it is happening.
As a workaround, you can use xf:setindex to explicitly set the repeat index after having inserted the new node in the data.

How to refresh binding of controls after modifying bound resources in Orbeon/XForms?

Following is the instance model for my form:
<xforms:model id="fr-form-model">
<!-- Main instance -->
<xforms:instance id="fr-form-instance">
<form>
<section-1> <age>20</age> <first-name>Tseveen</first-name>
</section-1>
</form>
</xforms:instance>
<!-- Bindings -->
<xforms:bind id="fr-form-binds" nodeset="instance('fr-form-instance')">
<xforms:bind id="section-1-bind" nodeset="section-1">
<xforms:bind id="age-bind" name="age" nodeset="age" />
<xforms:bind id="first-name-bind" nodeset="first-name"
name="first-name" />
</xforms:bind>
</xforms:bind>
<!-- All form resources -->
<!-- Don't make readonly by default in case a service modifies the resources -->
<xforms:instance id="fr-form-resources" xxforms:readonly="false">
<resources> <resource xml:lang="en"> <section-1>
<age> <label>Age</label> <hint>Years since borning</hint> <help>Substract birth date from current date</help>
<alert>Age is required!</alert> </age> <first-name> <label>First
name</label> <hint>Enter first name</hint> <help>a.k.a given name</help> <alert>First
name is required!</alert> </first-name> </section-1> </resource> </resources>
</xforms:instance>
As you can see controls are bound to resources in fr-form-resources.
I have an action like:
<xforms:setvalue
ref="xxforms:instance('fr-form-resources')/resources/resource/section-1/age/label"
value="'Doljin'" />
The idea is changing the label text of the control.
How can one refresh binding of controls after modifying bound resources in Orbeon/XForms so that the visual label text can be updated?
This should happen automatically without you having to do anything. If this isn't happening in your case, it might be because you don't modify the right node, or the control isn't bound to the right node. If you think you are changing the right node, please provide a minimal example that shows the problem.

Instance data on success page

I have made a page that is suppose to be a common exit point (success page) for all Orbeon applications made both manually creating XFroms and by Orbeon Builder. The page is really simple as it is only supposed to show a generic message that is specified in a form that gets redirected to the page after submission. This feels like a trivial task, yet I have struggled a lot with it.
The documentation says:
The "POST" solution
If your XForms page responds to an HTTP POST containing XML, then it can access the content of the POST data with a special URL called input:instance:
<xforms:instance id="user-data" src="input:instance"/>
This results in the user-data instance being populated with the XML data posted to the XForms page. It's as easy as this!
NOTE: Nothing prevents you to combine this method with getting data from the request or a service.
My page-flow.xml
<config xmlns="http://www.orbeon.com/oxf/controller"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:oxf="http://www.orbeon.com/oxf/processors">
<page id="main" path-info="/thankyou/" view="thankyou.xhtml"/>
<page id="test" path-info="/thankyou/test" view="test.xhtml">
<action when="/form/fromPage = 'test'">
<result page="main"/>
</action>
</page>
<epilogue url="oxf:/config/epilogue.xpl"/>
</config>
thankyou.xhtml
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xxforms="http://orbeon.org/oxf/xml/xforms">
<xhtml:head>
<xhtml:title>Thank you</xhtml:title>
<xforms:model xmlns:xforms="http://www.w3.org/2002/xforms">
<xforms:instance id="form-instance" src="input:instance"/>
<xforms:bind id="form-binds" nodeset="instance('form-instance')">
<xforms:bind id="success-bind" ref="/form/success/successPageText"/>
</xforms:bind>
</xforms:model>
</xhtml:head>
<xhtml:body>
<xhtml:p>
<xhtml:output ref="instance('form-instance')/form/success/successPageText"/>
</xhtml:p>
<xhtml:p>
<xhtml:output bind="success-bind"/>
</xhtml:p>
<xhtml:p>
<xhtml:a href="http://www.google.com">Away from here</xhtml:a>
</xhtml:p>
</xhtml:body>
</xhtml:html>
test.xhtml
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:xxforms="http://orbeon.org/oxf/xml/xforms">
<xhtml:head>
<xhtml:title>Thankyou page test</xhtml:title>
<xforms:model id="form-model">
<xforms:instance id="form-instance">
<form>
<input>text here</input>
<fromPage>test</fromPage>
<success>
<successPageText>
This is a test.
</successPageText>
</success>
</form>
</xforms:instance>
<xforms:bind id="form-binds" nodeset="instance('form-instance')">
<xforms:bind id="input-bind" ref="/form/input" type="xs:string" required="true()"/>
</xforms:bind>
<xforms:submission id="main-submission" method="post" action="/thankyou/test"
ref="instance('form-instance')" validate="false" replace="all"/>
</xforms:model>
</xhtml:head>
<xhtml:body>
<xhtml:table>
<xhtml:tr>
<xhtml:td>
<xforms:input bind="input-bind" id="input-control">
<xforms:label>Type something here </xforms:label>
</xforms:input>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td>
<xforms:submit submission="main-submission" id="submit-control">
<xforms:label>Test</xforms:label>
<xforms:setvalue ev:event="DOMActivate">submit</xforms:setvalue>
</xforms:submit>
</xhtml:td>
</xhtml:tr>
</xhtml:table>
</xhtml:body>
</xhtml:html>
The thankyou page gets loaded when submitting from the test page, but the value set for the 'successPageText' is not shown.
I have tested with a Java servlet that when submitting from other pages/forms the xml data is included with the post, but I am unable to figure how to use it on the thankyou page.
The main reason your example doesn't work is that in test.xhtml you are posting to yourself. Instead, you should post to the target page. So write the submission as:
<xforms:submission id="main-submission" method="post"
action="/20110920-so-thankyou/"
ref="instance('form-instance')" validate="false" replace="all"/>
The pattern of posting to yourself, and then determining in page-flow.xml what the next page should be, is considered to be deprecated. It still works, there are still situations where it makes sense, but in the majority of the cases, the cost of the added complexity is higher than the benefits you get from this decoupling.
Finally, a couple of things very specific to your example:
In thankyou.xhtml, you were using <xhtml:output>, which you'll want to change to <xforms:output>.
The XPath expression in the first output should be instance('form-instance')/success/successPageText without form. Remember: instance() returns the root element, not the document element.

How to do something with selected values of an xforms:select every time they change?

I have this problem with XForms I am running on Orbeon Forms. I am using a fr:box-select control as follows:
<fr:box-select bind="box-select-bind" id="box-select-control">
<xforms:action ev:event="xforms-value-changed">
<xxforms:variable name="selected-value" select="."/>
<xforms:message level="modal">Hello:<xforms:output select="$selected-value" />
</xforms:message>
</xforms:action>
<xforms:itemset nodeset="instance('codes')/box-select/item">
<xforms:label ref="label"/>
<xforms:value ref="value"/>
</xforms:itemset>
</fr:box-select>
The binding is to a simple XML file:
<box-results></box-results>
The codes XML looks like:
<box-select>
<item>
<label>Cat</label>
<value>cat</value>
</item>
<item>
<label>Dog</label>
<value>dog</value>
</item>
<item>
<label>Bird</label>
<value>bird</value>
</item>
<item>
<label>Fish</label>
<value>fish</value>
</item>
</box-select>
When I check entries in the box, my node <box-results> gets updated with the selected values separated by a space, which seems to be what is expected. However, I can't seem to find any documentation on how to process the selected values. I want to get access to what value was just selected, de-selected and use the value of this item in an xpath. So, if a value was selected then I would do this:
<setvalue
ref="somexpath[id=$selected-value]/display
value="'true'"/>
And if a value was deselected I would do this:
<setvalue
ref="somexpath[id=$selected-value]/display
value="'false'"/>
Basically, I just want to know the event to use, and how to get access to the value when it fires. Then I want to use this value in an xpath. I am going to use this to hide/display portions of the form. Using the xforms-value-changed event the Xpath "." doesn't return what I would expect, as it does in "select1" controls.
I can loop through all the values that are selected like so:
<xforms:action ev:event="xforms-select" xxforms:iterate="for $s in tokenize(instance('data-inst')/box-results,'\s')return xxforms:element('text',$s)">
<xforms:message level="modal">Hello selected:<xforms:output select="$s" />
</xforms:action>
However, this isn't exactly what I need. I might be able to make this work, but it would require a lot more work because I need to do know what ones are deselected to change the display for the user.
Since in your case you don't need to know specifically which value changed, you can on value change reset all the values in somexpath[id=$selected-value] as needed. You can do this with the following code which uses just <xforms:setvalue> with an xxforms:iterate:
<xforms:action ev:event="xforms-value-changed">
<xxforms:variable name="selected-values" select="tokenize(., '\s+')"/>
<xforms:setvalue xxforms:iterate="instance('codes')/item"
ref="#selected">false</xforms:setvalue>
<xforms:setvalue xxforms:iterate="$selected-values"
ref="for $v in . return instance('codes')/item
[value = $v]/#selected">true</xforms:setvalue>
</xforms:action>
Also see the full source of an example that uses the above snippet.
you can use ev:event="xforms-select" and ev:event="xforms-deselect" events.
Also the selected value can be captured using event('xxforms:item-value')
Here is how it would be used in case anyone is wondering:
<xforms:action ev:event="xforms-select">
<xxforms:variable name="selected" select="event('xxforms:item-value')" />
<xforms:message level="modal">Select:<xforms:output value="$selected" /></xforms:message>
</xforms:action>
<xforms:action ev:event="xforms-deselect">
<xxforms:variable name="deselected" select="event('xxforms:item-value')" />
<xforms:message level="modal">deSelect:<xforms:output value="$deselected" />
</xforms:message>
</xforms:action>

Resources