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

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>

Related

Orbeon form: Disable form fields after clicking "Submit"

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.

How to extend a component screen in Moqui?

I'm trying to modify the structure of a screen. Specifically, I want to add button to System/dashboard.xml. The problem is the screen doesn't iteratively build its buttons from its subscreens as webroot/apps/AppList.xml does. They are hardcoded.
I considered two solutions:
Just override dashboard.xml from my component
Inject javascript into dashboard.xml to dynamically create the button
Solution 1 would work but it's obviously not desired as it could create clashes with other components also wanting to modify dashboard.xml and using the same method.
I haven't been able to get around implementing solution 2, as, if I understand correctly, the mounted dashboard.xml subscreen with the javascript would not execute in dashboard.xml as it's not in the url path. A solution would be to reverse the mount order, and mount dashboard.xml under the javascript screen but that would create a problem similar to solution 1.
So, is there a standard or recommended way of doing this?
Instead of extending it there are three ways I am thinking you can do it.
The first one is including the screen in you extended screen using the tag
<include-screen location"component://path/to/component"/>
You can combine it with <include-screen ...share-scope="true" /> so that both pages operate in the same context.
The second one is using a parametrization so when you include the screen depending on a flag the third button is added or not:
<actions>
<set field="parameterName" value="1"/> <!-- or 0 -->
</actions>
<widgets>
...
<include-screen location"component://path/to/component"/>
...
</widgets>
And in dashboard.xml
<parameter name="parameterName" />
<!-- then use conditional-field or if tag to show conditionally -->
The third one is trying to replicate the menu structure at webroot/apps/AppList.xml, just as tabs, and menus do.

How to use <p:blockUI> on whole view?

I want to use <p:blockUI> to block the whole view. But as it's attribute block does only accept ids as keywords and not e.g. #all, the only way I currently see is to have a naming container (e.g. <f:subview>) to wrap the whole content of the view.
Unfortunately that's semantically dirty and I would need to rename all absolute ids because a new unneccessary (except for <p:blockUI>) id-"prefix" has been created.
Is there a cleaner way to do this?
Assuming I understand correctly, you could simply add an id to h:body and reference that id in the block attribute of <p:blockUI>. Also, you wouldn't need to change the ids of your components. Quick example
<h:body id="wholeView">
<h:form>
<h:inputText/><br/>
<h:inputText/><br/>
<p:commandButton id="pnlBtn" value="Block Panel" type="button" onclick="bui.show()"/>
<p:blockUI block=":wholeView" widgetVar="bui"/>
</h:form>
</h:body>
Again, this is just a silly example which simply blocks the view for demonstration purposes. However, from what I understand from the answer below, you would need to be using Mojarra 2.1.8 or higher to use the id from h:body.
How to spefic the body id attribute in JSF 2?

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.

A better way to get the real ID of an component in a naming container

I got the following scenario:
I got several tabs (TabView is a naming container )
and in one of the I got a p:inputText which shows a dialog(which is located in other xhtml file) , now I want the dialog to update the p:inputText , the thing is that the id of the p:inputText is unknow (JSF adds some prefix to it)
<h:form id="hoursReportFrm">
<p:inputText id="comment4Dialog" value="#{hoursReportBean.aComment}"
onfocus="dlg1.show();"/>
I can't use this update="hoursReportFrm:comment4Dialog" in the dialog
ATM i looked at the example of this site JSF: working with component IDs (id vs clientId) (its from 2009)
and added binding to to inputtext , like thisbinding="#{lookup.components.comment4Dialog}" and in the p:commandButton of the dialog I changed to update="#{lookup.clientIds.comment4Dialog}"
and It works just fine, but I'm looking for a better way , without the need to bind every component that I would like to access later...
Thanks ahead,
To be quite honest, I think the binding is probably the easiest route, however when I've been in that situation I've found composite components often offer a better solution than bindings. Depending on the situation (and again, its totally case by case) you can use a composite component to get around this problem. This allows you to reuse parts of a page creatively so that your specific updates don't take a lot of work and you can reuse the code.
An example of this might be:
//comp:myDialog
...
<composite:interface>
<composite:attribute name="update" />
<!-- Other attributes -->
</composite:interface>
<composite:implementation>
...
<!-- Implementation -->
<p:commandButton update="#{cc.attrs.update}"/>
...
</composite:implementation>
And here might be the component in use:
//for the sake of argument 'comp' as your library
<h:form id="someForm">
<p:inputText value="#{bean.changeMe}" id="changeMe"/>
</h:form>
<h:form id="dialog">
<!-- dialog here -->
<comp:myDialog update="someForm:changeMe" />
</h:form>
By separating this view into a piece of reusable code you might be able to get around the burden of specifying the full path because it is now much easier to reuse. However, I think it is a toss up of a binding or the composite component depending on the specific case. For reuse, make a new object (component) and reuse it. If you're dealing with a highly dynamic environment: bind it.
I'm not an expert by any means, but generally speaking the above has gotten me out of a lot of tough situations.
EDIT: on a re-read you should also make sure that the tab-view isn't lazily loaded and take a look at the rendering to make sure the path is correct (inspect the ID). I've had problems (in older versions of Primefaces) where sometimes the id was nested inside a p:outputPanel or in rare cases the subview id. It might be a very simple fix by specifying the full path ':subview:form:component' though that shouldn't be the case.

Resources