How to do an xforms:insert without the need of xforms:delete at the end? - orbeon

<xf:action ev:event="xforms-model-construct">
<xf:insert nodeset="instance('subInstance')/type" origin="instance('defaultType')/type"/>
</xf:action>
I want to populate an instance based on another one. I can do this using xf:insert as shown above.
However, I realised that the instance 'subInstance' must contain an empty type element before starting the xf:inserts.
<subInstance>
<type/>
</subInstance>
So after all the xf:inserts, I need do the following to delete the first empty one:
<xf:delete nodeset="instance('subInstance')/type" at="1" />
Is there something wrong with this method or is there a way I can insert directly without an initial empty ?

Two answers:
You don't really need an initial type element
Your original instance can simply be:
<subInstance/>
And then you can insert into the subInstance element with:
<xf:action ev:event="xforms-model-construct">
<xf:insert
context="instance('subInstance')"
origin="instance('defaultType')/type""/>
</xf:action>
Using context without nodeset or ref says that you want to insert into the node pointed to by context.
You can still do what you want but with XForms 2.0 support
If you want to keep the original nested type element, you could write this:
<xf:action ev:event="xforms-model-construct">
<xf:insert
nodeset="instance('subInstance')"
origin="
xf:element(
'subInstance',
instance('defaultType')/type
)
"/>
</xf:action>
By targeting the root element of the destination instance, the entire instance will be replaced. This is already the case with XForms 1.1.
With the origin attribute's use of the xf:element() function from XForms 2.0, you can dynamically create an XML document rooted at subInstance and containing only the type elements from the defaultType instance.
To make this even more modern, you would replace nodeset with ref, as nodeset is deprecated in XForms 2.0:
<xf:action ev:event="xforms-model-construct">
<xf:insert
ref="instance('subInstance')"
origin="
xf:element(
'subInstance',
instance('defaultType')/type
)
"/>
</xf:action>

Related

Orbeon disable custom submit to external webservice after submit

How can I disable a custom submit button after submit?
Below you can find my part of code to send:
<xf:trigger bind="booking-bind" id="booking">
<xf:label>
<xh:span>
<xf:output value="'Send'"/>
</xh:span>
</xf:label>
<xf:action ev:event="DOMActivate">
<xf:setvalue ref="instance('fr-form-instance')/submission_type">SendBooking</xf:setvalue>
<xf:setvalue ref="instance('fr-form-instance')/submission_extra_info">//booking[1]</xf:setvalue>
<xf:action type="xpath" xmlns:process="java:org.orbeon.oxf.fr.process.SimpleProcess">
process:runProcessByName('oxf.fr.detail.process', 'send')
</xf:action>
</xf:action>
</xf:trigger>
I am using this solution: Orbeon upgrade from 3.9 to 4.5 : Customized submit for saving forms
I see your trigger has a booking-bind bind. You could have a readonly MIP saying whether the button should be readonly. For example:
<bind id="booking-bind" readonly=". = 'sent'"/>
Then, in your action, do:
<xf:setvalue ref="xxf:bind('booking-bind')" value="'sent'"/>
This will cause the trigger to become readonly.
By the way we have an issue to tackle this better.

How to insert nodes after specific node of an instance in Orbeon?

I have an instance in model:
<Exams>
<ExamCode>14</ExamCode>
</Exams>
<Exams>
<ExamCode>15</ExamCode>
</Exams>
I want to iterate on all elements and add after ExamCode element some nodes but without parent.
My instance after iterate should be like this:
<-- Wanted -->
<Exams>
<ExamCode>14</ExamCode>
<ExamTitle></ExamTitle>
<ExamDescription>/ExamDescription>
</Exams>
<Exams>
<ExamCode>15</ExamCode>
<ExamTitle></ExamTitle>
<ExamDescription></ExamDescription>
</Exams>
What i have tried is this:
Instance to add:
<!-- instance nodes to add-->
<xf:instance id="examRelatedNodes">
<ExamTitle/>
<ExamDescription/>
</xf:instance>
Adding "examRelatedNodes" instance to all repeated Exams nodes:
<!-- insert examRelatedNodes per Exam -->
<xf:action ev:event="xforms-ready" xxf:iterate="instance('fr-form-instance')/Exams">
<xf:insert context="." origin="instance('examRelatedNodes')"/>
</xf:action>
But I get an error that instance to add, should have parent!
I have read the documentation, this from the orbeon blog, but in all paradigms i find, the elements of to-add-instance have a parent, but in my case i don't want to have.Following these examples with parent node, i am able to add them, BUT with parent node "ParentOfExtraNodes" that i don't want:
<-- Not wanted -->
<Exams>
<ExamCode>14</ExamCode>
<ParentOfExtraNodes>
<ExamTitle></ExamTitle>
<ExamDescription>/ExamDescription>
<ParentOfExtraNodes/>
</Exams>
<Exams>
<ExamCode>15</ExamCode>
<ParentOfExtraNodes>
<ExamTitle></ExamTitle>
<ExamDescription>/ExamDescription>
<ParentOfExtraNodes/>
</Exams>
I am using Orbeon Forms 4.5 (XForms implementation).
What you are doing looks about right. But in your instance examRelatedNodes, you need to have a root element, say:
<xf:instance id="examRelatedNodes">
<RelatedNodes>
<ExamTitle/>
<ExamDescription/>
</RelatedNodes>
</xf:instance>
And then your insert will become:
<xf:insert context="." origin="instance('examRelatedNodes')/*"/>

Catching save event in Form Builder

I would like to send submission after form has been saved in Form Builder, I was trying something like this at first (in my XBL file):
<xf:action ev:event="fr-data-save-done" ev:observer="fr-form-model">
<xf:message event="#all" level="modal">Saved</xf:message>
<xf:send submission="my-submission" ev:event="#all"/>
</xf:action>
The code above is placed in XBL file between xbl:template, outside xbl:model (though I tried to put it inside xbl:model with no luck).
Unfortunately it's not working, after I save my form in Form Builder message is not shown.
Anyone got idea why it's not working?
You could place by hand an event handler like this:
<foo:bar id="my-component-id" bind="my-bind">
<xf:dispatch
event="fr-data-save-done"
observer="fr-form-model"
name="my-custom-event"
targetid="my-component-id"/>
</foo:bar>
The handler doesn't have to be within the element:
<foo:bar id="my-component-id" bind="my-bind"/>
<xf:dispatch
event="fr-data-save-done"
observer="fr-form-model"
name="my-custom-event"
targetid="my-component-id"/>
And inside the XBL component:
<xbl:binding id="my-binding-id" element="foo:bar">
<xbl:handlers>
<xbl:handler event="my-custom-event" phase="target">
... XForms actions here ...
</xbl:handler>
</xbl:handlers>
...
</xbl:binding>

Custom XBL component for submitting form

I'm trying to implement a custom xbl component to submit the form to an external service, perform validation and handle the validation results. The version of orbeon is 4.4-CE deployed on JBoss 7.1.1.Final with MySQL persistence layer.
<xbl:binding element="fr|custom-submit" id="fr-custom-submit" xxbl:mode="lhha binding value">
<xbl:implementation>
<xf:model id="custom-submit-model">
<xf:instance id="validation-res">
<dummy/>
</xf:instance>
<!-- External validation submission -->
<xf:submission id="form-submission" ref="instance('fr-form-instance')"
action="http://localhost:8080/webapp/services/task/submitData" method="post"
replace="instance" instance="validation-res">
<xf:delete ev:event="xforms-submit" ref="//#v:*"/>
<xf:action ev:event="xforms-submit-done">
<!-- Insert external validation results when done -->
<xf:insert ref="." origin="instance('validation-res')/v:data/*"/>
<!-- Handle the valid/invalid result -->
</xf:action>
</xf:submission>
</xf:model>
</xbl:implementation>
<xbl:template>
<fr:button ref="xxf:binding('fr-custom-submit')">
<xf:label>
<xh:img src="/apps/fr/style/images/silk/disk.png"/>
<xh:span>Custom save</xh:span>
</xf:label>
<xf:send ev:event="DOMActivate" submission="form-submission"/>
</fr:button>
</xbl:template>
</xbl:binding>
Upon submitting the form the following exception occurs in the log files:
Empty single-node binding on xf:submission for submission id: form-submission |
I cannot figure out, what the exception means and if the cause of the problem is the strong encapsulation as described here.
Is it in general possible to write a custom xbl component for submitting a form? How can I overcome the above mentioned problem?
Regards
It is indeed an issue related to encapsulation, and using xxf:instance() allows you to break the encapsulation. So in your case, the submission would do:
ref="xxf:instance('fr-form-instance')"

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