Orbeon form: Disable form fields after clicking "Submit" - orbeon

I'm trying to configure "Send" process to set all fields to readonly, but it didn't work. Here is my configuration in properties.xml:
<property as="xs:string" name="oxf.fr.detail.process.send.*.*">
require-valid
then save
then success-message("save-success")
then xf:setvalue(ref = "//*[xf:readonly]", value = "true()")
</property>
Thanks for all suggestions!

You cannot set the "readonly-ness", in an imperative imperative way, with a xf:setvalue. Instead, the "readonly-ness" is define in a declarative way. In your case, I would recommend that:
When the form is submitted, you change the stage of the form, say to "submitted". In your process, you can do so with (doc):
set-workflow-stage(name = "submitted")
In Form Builder, you use a form level formula (doc) to declare that the whole form is readonly if the stage is "submitted". The formula will look like:
fr:workflow-stage-value() = 'submitted'
Also see the blog post New workflow capabilities in Orbeon Forms 2020.1.

Related

Orbeon: Make all non-read-only fields required (globally)

I have a big form with many input controls (400+). For many of them, I added rules so they are read-only unless a certain other field is set to "no".
Example:
Do you agree with XXX? yes [ ] no [ ]
Reason: __________________ <--(textfield that is read-only unless "no" is selected)
Now I would like that all non-read-only fields are required. How can I do this without adding a (conditional) required-rule to every single input control? Because doing so would take forever and also it seems like bad practice to me to apply a rule that we can formulate globally to every single element...
I thought about using a script and doing something like this:
<xf:action ev:event="xforms-value-changed" type="javascript">
ORBEON.jQuery('input, textarea, select').each(function() {
if (ORBEON.jQuery(this).is(':disabled')) {
// what now??? is there something like "ORBEON.jQuery(this).makeRequired();" ?
}
});
</xf:action>
You don't want to do this in JavaScript, but could do it in XForms. Assuming you're creating the form with Form Builder, you can do this by editing the source of form, and adding the following inside the <xf:model>. With this you are, quite plainly I think, saying that all nodes are required if they are not read-only.
<xf:bind ref="instance('fr-form-instance')//*" required="not(xxf:readonly())"/>
You can also reset the values of all read-only fields by "overriding" the "save" process as follows. Note that everything here is standard, and only the xf:setvalue(ref = "//*[xxf:readonly()]") is added.
<property as="xs:string" name="oxf.fr.detail.process.save-final.*.*">
require-uploads
then validate-all
then xf:setvalue(ref = "//*[xxf:readonly()]")
then save
then new-to-edit
then success-message("save-success")
recover error-message("database-error")
</property>

Use placeholders with <f:all bean />

In Grails, you can generate a form using <f:all bean="beanName" />. And while the generated form looks great, I was wondering if it would be possible to have a placeholder in the field, so that the result becomes something like:
<input type="text" name="question" placeholder="type your question here" />
I tried using the attributes validation in Grails, like this:
class Question {
static constraints = {
question(size:5..100, attributes:[placeholder:"type your question here"])
}
}
But it doesn't seem to have any effect on the generated HTML.
Just in case there's any confusion, the f:all tag is provided by the fields plugin. I don't think there's any way you can specify the placeholder attribute via the domain class constraints, but there are a few other options.
One option is to define a custom (GSP) template for this property and specify the placeholder attribute therein. The path to this template will depend on which version of the plugin you're using, but you can find the details here.
Alternatively, if you render each field individually with f:field, rather than using f:all you can pass additional attributes to the input field, e.g.
<f:field bean="person" property="gender"
widget-placeholder="type your question here"/>
In earlier versions of the plugin (before 1.5), the attribute should be named input-placeholder instead, e.g.
<f:field bean="person" property="gender"
input-placeholder="type your question here"/>

How is the path expression built when calling the search API for Form Builder?

When accessing the Form Builder summary, which lists the forms I currently have access to, I see the search API is called with
<query name="application-name"
path="xh:head[1]/xf:model[#id = 'fr-form-model'][1]/xf:instance[#id = 'fr-form-metadata']/*[1]/application-name[1]"
inline-label="" type="xs:string" control="output"
search-field="true" summary-field="true" match="substring" />
How/where is the path expression built?
It is built by the Form Runner summary page, the same way for Form Builder as for other forms, looking for elements with the fr-summary class.
So the summary page can find those element, Form Builder has hidden outputs with that class.
Those outputs reference real binds in Form Builder's model.
Form Runner's summary page builds the path expression by going through the ancestors of the bind mentioned in the previous points, and building and building an expression concatenating the ref on those binds.

Dynamically add attribute to struts2 UI tag

Is there a way to dynamically add an attribute to a struts 2, tag UI tag such as a textfield?
The reason is that I want to add a readOnly form field attribute to an <s:textfield/>, depending on an action's method result. I cannot use readOnly="%{isReadOnly()}" since once the attribute is defined, the form element is read-only, no matter what value it has. And wrapping each form field into an <s:if/> tag is pretty cumbersome and results in a lot of code duplication.
I would also like to avoid JavaScript for interoperability reasons and for not relying on the browser's scripting settings.
If the issue is to use the built in struts2 functionality then one easy option is to render your view with freemarker, which readily supports the dynamic addition of attributes.
If you are using conventions, it is VERY trivial you just need to create a file with a ".ftl" extension, if you are using xml it is also very easy just use the freemarker result type (see here for greater description):
<action name="test" class="package.Test">
<result name="success" type="freemarker">/WEB-INF/content/testView.ftl</result>
</action>
Here is example view using a map to dynamically add attributes (example also taken from liked page):
<#s.textfield name="test" dynamicAttributes={"placeholder":"input","foo":"bar"}/>
The dynamicAttributes would be extremely useful in all JSP UI tags but alas it is not currently implemented.
NOTE: There is one error/omission in the above link. It tells you to add the following line which causes an error in my environment (simply the line is not needed).
<#assign s=JspTaglibs["/WEB-INF/struts.tld"] />
That is, this line in a file all by it self is sufficient for rendering a text element, no explicit tag library declaration needed!
<#s.textfield name="test" dynamicAttributes={"placeholder":"input","foo":"bar"}/>
There are a number of advantages to using freemarker over plain JSPs, so taking a moment to explore the syntax and using it for this one case may prove useful later.

How can I create my own validation rule in orbeon xforms?

Here's the problem, I need to validate the form before submitting in the next way, before user can submit anything he should click "Save" button, if he tries to click "Submit" one receives message something like "You should save form before submit".
First I thought that I can add system field to the form like save-indicator, add constraint to like that
<xforms:bind id="isSaved-bind" nodeset="isSaved"
name="isSaved" type="xforms:string" constraint="number(.)=1" required="true()"/>
And add
<xforms:setvalue ref="xxforms:instance('fr-form-instance')/person/isSaved">1</xforms:setvalue>
to actions when "Save" button beeing clicked.
But, the problem is that I have to rewrite all existing forms to insert new code there.
Is there any posibility to make global variable like "isSaved" and check it for every form, before submit, and show error message if user didn't save form?
Or may be there another way that I can't see?
Will be appreciated for any answers.
Form Runner keeps track of whether the form is clean or dirty, and you can access that information in xxforms:instance('fr-persistence-instance')/data-status. The code handling the submit is in apps/fr/includes/persistence/persistence-model.xml. There you could change the listener for DOMActivate on fr-submit-button to read like:
<xforms:action ev:event="DOMActivate" ev:observer="fr-submit-button">
<xforms:action if="instance('fr-persistence-instance')/data-status = 'clean'">
<xforms:setvalue ref="instance('fr-persistence-instance')/submit-or-save-or-send">submit</xforms:setvalue>
<xforms:dispatch name="fr-save-action" target="fr-persistence-model">
<xxforms:context name="fr:check-data-valid" select="true()"/>
</xforms:dispatch>
</xforms:action>
<xforms:action if="instance('fr-persistence-instance')/data-status = 'dirty'">
<xforms:message>You must save form before submitting it.</xforms:message>
</xforms:action>
</xforms:action>
Note that persistence-model.xml is in orbeon-form-runner.jar. To change that file, extract it from there, and place it in the WEB-INF/resources/apps/fr/includes/persistence/persistence-model.xml. That version on WEB-INF/resources will take precedence over the one in the jar file. Also note that these type of changes that rely on the internals of Form Runner or Form Builder have a chance to break when upgrading to a new version of Orbeon Forms. So you might want to carefully keep track of them, so you can more easily reapply the changes when you upgrade.
I use a global flag indicator to check if the form is saved before closing the window or submit and it works pretty well.
This information is cleary explained in this wiki.
All the best!

Resources