Instance data on success page - orbeon

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.

Related

Exception in client-side code when xxforms:dialog is within an xforms:repeat

I have encountered a glitch in Orbeon 2017.1 that did not occur in late 2015/early 2016 versions of the software: an error popup which has occurred when adding certain elements into the xforms:instance
Exception in client-side code.
Message: l is undefined
File: http://localhost:8080/orbeon/xforms-server/orbeon-266479e766510e28f420e559b3a49c43f8b18400.js
Line number: 79
After a few hours of testing, I have narrowed it down to the following. When an xxforms:dialog appears within a repeated node (xforms:repeat), and new elements are added, the error occurs. Note that the error does not occur if the the element already exists by xforms-ready. To summarize my problem, I have a generic XBL component that will display an xxforms:dialog of attributes that can be edited, as derived dynamically by reading an XSD. This dialog can appear many places within an XForms application, for virtually any element. If the element in which the XBL is not repeatable (but added by DOMActivate), there is no error. Only in xforms:repeat.
<head>
<xforms:model>
<xforms:instance id="test">
<model xmlns="http://null">
<element1/>
</model>
</xforms:instance>
<xforms:instance id="element2-template">
<element2 xmlns="http://null"/>
</xforms:instance>
<xforms:instance id="element1-template">
<element1 xmlns="http://null"/>
</xforms:instance>
</xforms:model>
<xi:include href="dialog.xbl" xxi:omit-xml-base="true"/>
</head>
<body>
<h1>Test</h1>
<xforms:group ref="instance('test')">
<div>
<xforms:trigger appearance="minimal">
<xforms:label>Insert Element1</xforms:label>
<xforms:insert ev:event="DOMActivate" context="." nodeset="./child::node()[last()]" origin="instance('element1-template')"/>
</xforms:trigger>
<xforms:trigger appearance="minimal">
<xforms:label>Insert Element2</xforms:label>
<xforms:insert ev:event="DOMActivate" context="." nodeset="./child::node()[last()]" origin="instance('element2-template')"/>
</xforms:trigger>
</div>
<div>
<!-- this works:
<div>
<xforms:input ref="my:element1">
<xforms:label>Element1</xforms:label>
</xforms:input>
</div>
<my:dialog/>-->
<xforms:repeat nodeset="my:element1">
<div>
<xforms:input ref=".">
<xforms:label>Element1</xforms:label>
</xforms:input>
</div>
<!-- dialog does not work within newly added elements in a repeat on this level -->
<my:dialog/>
</xforms:repeat>
<hr/>
</div>
<!-- this works: insert element 2 after xforms-ready -->
<xforms:group ref="my:element2">
<div>
<xforms:input ref=".">
<xforms:label>Element1</xforms:label>
</xforms:input>
</div>
<my:dialog/>
</xforms:group>
</xforms:group>
</body>
Here is the XBL:
<xbl:xbl xmlns="http://www.w3.org/1999/xhtml" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xxf="http://orbeon.org/oxf/xml/xforms" xmlns:xbl="http://www.w3.org/ns/xbl" xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fr="http://orbeon.org/oxf/xml/form-runner" xmlns:my="http://null">
<xbl:binding id="my-dialog" element="my|dialog">
<xbl:template>
<xforms:group xbl:attr="model context ref bind" xxbl:scope="outer">
<xbl:content includes="xforms|label,xforms|help,xforms|hint,xforms|alert"/>
<xforms:group xxbl:scope="inner">
<xforms:var name="binding" as="node()?">
<xxf:sequence select="." xxbl:scope="outer"/>
</xforms:var>
<div>
Iside the XBL:
<xforms:trigger appearance="minimal">
<xforms:label>Click for dialog</xforms:label>
<xforms:action ev:event="DOMActivate">
<xxf:show dialog="element-attributes"/>
</xforms:action>
</xforms:trigger>
</div>
<xxf:dialog id="element-attributes" appearance="full" level="modal" close="true" draggable="true" visible="false">
<xforms:label>Dialog</xforms:label>
<div>Here's the dialog text</div>
</xxf:dialog>
</xforms:group>
</xforms:group>
</xbl:template>
</xbl:binding>
</xbl:xbl>
This form will load without errors. You can click the "Click for dialog" trigger in the XBL portion to show the xxforms:dialog because element1 is already in the model. However, if you click the trigger to add another element1, there will be an error dialog in client-side code. If you click the trigger to add element2, there's no error because element2 is not repeatable. You can therefore click the "Click for dialog" within element2 and the xxforms:dialog will appear.
Is there a workaround for this, or is this a bug in the current version of Orbeon? It did work in the version I ran earlier in 2017.
Indeed, the issue you reported does exist in Orbeon Forms 2017.2 (and maybe earlier version). This issue is now fixed, and the fix will be included 2018.1 and subsequent releases, as well as in 2017.2.1.

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.

Orbeon : One submission after another

In my form file I have a submission load-data-submission which fetches some data from database, it is called on xforms-ready :
<xf:model>
...
<xf:action ev:event="xforms-ready" ev:observer="fr-form-model" if="true()">
<xf:send submission="load-data-submission"/>
</xf:action>
...
</xf:model>
Now, I have an XBL controll which is used in this very same form. There is another submission which also fetches data etc, let's call it rest-submission. Now, I would like the rest-submission (the one inside XBL) to be called right after my load-data-submission (the one inside form file) would fetch data.
How would I do that ? I've tried put inside XBL
<xf:action ev:observer="load-data-submission" ev:event="xforms-submit-done">
<xf:send submission="rest-submission"/>
</xf:action>
with no luck.
Thanks in advance.
To avoid id clashes and enable encapsulation, XBL defines a new lexical scope for ids and a new XPath context. So if from inside the XBL you refer to id load-data-submission, this refers to a load-data-submission defined within the XBL, which is most likely non-existent in your case. To reference ids outside of the XBL, you need to change the scope with the xxbl:scope="outer" attribute. The following example illustrates how to do that:
<xh:html xmlns:xh="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xbl="http://www.w3.org/ns/xbl"
xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:example="http://example.com/">
<xh:head>
<xf:model>
<xf:submission
id="get-states"
method="get"
resource="/xforms-sandbox/service/zip-states"
replace="instance"
instance="states"/>
<xf:instance id="states">
<empty/>
</xf:instance>
</xf:model>
<xbl:xbl>
<xbl:binding element="example|simple">
<xbl:implementation>
<xf:model id="simple-model">
<xf:instance>
<internal/>
</xf:instance>
</xf:model>
</xbl:implementation>
<xbl:template>
<xf:group>
<xf:message ev:observer="get-states"
ev:event="xforms-submit-done"
xxbl:scope="outer"
value="'Got event'"/>
</xf:group>
</xbl:template>
</xbl:binding>
</xbl:xbl>
</xh:head>
<xh:body>
<example:simple/>
<xf:trigger>
<xf:label>Get states</xf:label>
<xf:send submission="get-states" ev:event="DOMActivate"/>
</xf:trigger>
</xh:body>
</xh:html>

Passing parameters to XBL in Orbeon

I've created these two simple files , view.xhtml :
<html xmlns="http://www.w3.org/1999/xhtml"
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:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xxf="http://orbeon.org/oxf/xml/xforms">
<head>
<title>Test</title>
<xf:model>
<!-- Instance that contains all the books -->
<xf:instance id="people-instance">
<people xmlns="">
<person>
<test/>
</person>
</people>
</xf:instance>
<xf:bind id="test-bind" name="test" ref="person/test"/>
</xf:model>
</head>
<body>
<xf:input id="test-control" bind="test-bind">
<xf:label>THIS</xf:label>
</xf:input>
<fr:my-name test="'test'">
</fr:my-name>
</body>
And my-name.xbl :
<xbl:xbl 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:ev="http://www.w3.org/2001/xml-events"
xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:xbl="http://www.w3.org/ns/xbl"
xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
xmlns:fb="http://orbeon.org/oxf/xml/form-builder">
<xbl:binding element="fr|my-name" id="fr-my-name" xxbl:mode="lhha binding value">
<metadata xmlns="http://orbeon.org/oxf/xml/form-builder" xmlns:xf="http://www.w3.org/2002/xforms">
<templates>
<view>
<fr:my-name id="" appearance="minimal" xmlns="" test="" >
</fr:my-name>
</view>
</templates>
<xf:input ref="#test">
<xf:label lang="en">Resource URI</xf:label>
</xf:input>
</metadata>
<xbl:template>
<!-- Local model and instance -->
<xf:var name="test-avt" xbl:attr="xbl:text=test" xxbl:scope="outer"/>
<xf:var name="test" xbl:attr="xbl:text=test" >
<xf:action ev:event="xforms-enabled xforms-value-changed">
<xf:setvalue ref="instance('test')" value="$test"/>
</xf:action>
<xxf:sequence value="xxf:evaluate-avt($test-avt)" xxbl:scope="outer"/>
</xf:var>
<xf:model>
<xf:instance id="test"><value/></xf:instance>
<xf:instance><value/></xf:instance>
<xf:submission id="save-submission" ref="instance('test')"
action="/exist/rest/db/orbeon/my-name/person.xml"
method="put" replace="none">
<xf:message ev:event="xforms-submit-error" level="modal">An error occurred while saving!</xf:message>
</xf:submission>
</xf:model>
<xf:input class="xforms-disabled" ref="xxf:instance('people-instance')//*[name() = saxon:evaluate($test)]" >
<xf:label>Your name</xf:label>
<xf:send ev:event="xforms-value-changed" submission="save-submission"/>
</xf:input>
</xbl:template>
</xbl:binding>
Now I would like pass parameters from my view.xhtml to XBL so when user inserts something in xf:input id='test-control' it would cause that the text will be saved in database.
The problem is, instead of what user actually inserted in my database I have :
<value>'test'</value>
instead of expected, f.e. if I insert 123
<value>123</value>
Anyone has any idea why my code doesn't work and how to fix this ?
Here is an example which works. I put both files together to make it easier to try.
A few things I changed:
If your test attribute is in fact an AVT, it shouldn't have quotes around it. So you have for example test="foo{42}" which evaluates to foo42, which, if I understand well, is the name of the XML element you want to observe.
You probably don't want saxon:evaluate($test): the AVT is already evaluated and the result available in the variable $test. There is no point evaluating the result as an XPath expression again.
The 2nd var must not have xbl:attr="xbl:text=test"
Optional: I used xxf:binding-context('fr-my-name')/root() instead of xxf:instance(), but xxf:instance() will work too (although its usage is not recommended).
Optional: I moved the XBL model under xbl:implementation. It makes it clearer that this is not dependent on the template.

XForms bind does not update when referenced instance data is updated

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>

Resources