Orbeon: Constraints on UI Parent Elements - orbeon

Does Orbeon have a way to provide validation on parents of UI elements? I've been testing it with some files from previous work on a different XForm engine, and I've noticed a difference in the handling of the errors on fields without direct UI inputs.
My instance looks like:
<set>
<value prop="1"/>
<value prop="2"/>
<value prop="3"/>
</set>
My UI section looks like:
<xf:group ref="set">
<h2>set</h2>
<xf:alert>Bigger Error</xf:alert>
<xf:repeat ref="value">
<xf:input ref=".">
<xf:label>Value</xf:label>
<xf:alert>Error</xf:alert>
</xf:input>
</xf:repeat>
</xf:group>
In the other engine, if a constraint such as <xf:bind ref="set" constraint="count(value) gt 3"/> failed, the error in the set group would show up in the UI. Is there a way for Orbeon to have this same behavior, or is that a non-standard implementation that I was unknowingly relying on?

In the case of Orbeon Forms, if you have an xf:group bound to an invalid node, just as for leaf controls, by default, you'll see the red icon with an exclamation point in the UI if you have <xf:alert> for the group.
If you don't have an <xf:alert>, the HTML element corresponding to the group will just have the xforms-invalid class in the DOM, which allows you, with CSS, to style the group in a way appropriate for your use case.

Related

How to get value from form builder as label of trigger?

I'm working on custom control in Orbeon. In form builder, in settings there is a field called buttonName. Its value is supposed to show as a label of button visible in form runner.
I'm moving an old file that supposedly worked on old version of orbeon. I tried changing the way I refer to the value from form builder. Below I show old code, without my changes.
In form builder metadata I have declared input with ref:
<xbl:binding element="fr|custom-input" id="fr-custom-input-binding" xxbl:mode="lhha binding value">
<!-- Orbeon Form Builder Component Metadata -->
<metadata xmlns="http://orbeon.org/oxf/xml/form-builder" xmlns:xf="http://www.w3.org/2002/xforms">
...
<control-details>
<xf:input ref="#buttonName">
...
Further on, there is a var to that binding
<xf:var name="binding" value="xxf:binding('fr-custom-input-binding')"/>
Finally, the reference in form runner:
<xf:trigger class="xbl-fr-custom-input-trigger">
...
<xf:label value="$binding/#buttonName"></xf:label>
</xf:trigger>
You want to access an attribute on the control itself:
<fr:custom-input buttonName="Your value">
This in contract to an attribute that you could have on the element the control is bound to, which is what $binding points to. So $binding/#buttonName is not the right expression to use here. Instead, inside your , you want to have:
<xf:var name="buttonName" xbl:attr="xbl:text=buttonName"/>
Then you can refer in XPath to the value of the attribute as $buttonName.

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>

wrong ids when render h:panelGroup's inside c:forEach

I have page where I render some h:panelGroup panels. Those panels are realized as plugins registered in a plugin registry on startup.
Part of the plugins api is a custom jsf component where I get the registered plugins for extension point and include their facelet templates by path:
<c:forEach items="#{pluginRegistry.getPlugins(point)}" var="extension">
<ui:include src="#{extension.path}" />
</c:forEach>
The page where I include the panels looks like:
<h:panelGrid id="dashboard" columns="3">
<cmf:insertPageFragments point="dashboardExtensionPoint" />
</h:panelGrid>
For every panel there are facelet templates like the one below:
<rich:panel id="caseDetailsPanel" header="panel label">
<!-- panel content -->
</rich:panel>
Now, the problem is that the very first panel in the list returned by the pluginsRegistry is rendered in the page with the provided id like formId:caseDetailsPanel for example. The rest of them have generated ids like formId:j_idt223 !!! Obviously if I want to rerender some of the panels, I can't do that.
That happens when environment is jboss AS 7.1 with JSF 2.1, richfaces 4.2.3.Final.
When deployed on jboss-eap-6.1 everything looks fine but for now I can't use this jboss version.
Any suggestions on how to workaround this issue?
There can not be multiple JSF components with the same ID. Each JSF component must have an unique ID. When dynamically creating JSF components using JSTL, you need to manually assign and ensure an unique ID, otherwise JSF will discard the provided ID and autogenerate an unique ID.
There are several ways to achieve this, depending on the concrete functional requirement and the existing code.
Use use the iteration index of <c:forEach>.
<c:forEach ... varStatus="loop">
...
<rich:panel id="caseDetailsPanel_#{loop.index}" ...>
This will generate caseDetailsPanel_0, caseDetailsPanel_1, etc depending on the current iteration index.
Use the unique identifier of the currently iterated item. It isn't clear based on the information provided so far if you have any, so here's just a fictive example assuming that the class behind #{extension} has an id property representing the technical DB identifier.
<c:forEach ... var="extension">
...
<rich:panel id="caseDetailsPanel_#{extension.id}" ...>
Wrap #1 or #2 if necessary in a <f:subview> with an unique identifier, so that you don't need to modify the includes.
<c:forEach ... varStatus="loop">
<f:subview id="panel_#{loop.index}">
<ui:include ... />
The <f:subview> creates a new NamingContainer around it, so you end up getting formId:panel_0:caseDetailsPanel, formId:panel_1:caseDetailsPanel and so on.
A completely different alternative would be to use <ui:repeat> instead of <c:forEach>. The <ui:repeat> does not run during view build time, but during view render time. This way there's physically only one <rich:panel id="caseDetailsPanel"> component in the component tree which is reused multiple times during generating HTML whereby JSF will take care of generating the right IDs with the <ui:repeat> index like so formId:repeatId:0:caseDetailsPanel. However, this in turn may cause trouble with <ui:include> as it also runs during view build time and thus can't get the #{extension} at hands.

widgetVar name collision in Primefaces in multiple cc:renderFacet

I have composite component, in which I have toolbar and datatable. I also defined facet which contains a form for manipulating data from datatable. Users define that facet for different kinds of data. Now, I have problem because I render that facet multiple times and now I have collisions for widgetVar names for Primefaces components. It is no possible to use insertChildren multiple times so I think this is only possible solution. Also I wouldn't like to force users of component to define 10 facets and write ui:include 10 times. Is there any other way to insert some facelet code in composite component, or is there any way to pass parameter to facet, and use that parameter to dynamically create widgetVar?
OK, after some time I just didn't succeeded to do what I wanted. First I had some composite component like this:
<cc:interface>
<!-- Attributes definition -->
<cc:facet name="form"/>
</cc:interface>
<cc:implementation>
<p:dialog><f:subview id="detailSubview1"><cc:renderFacet name="form"/></f:subview></p:dialog>
<p:dialog><f:subview id="detailSubview2"><cc:renderFacet name="form"/></f:subview></p:dialog>
<!-- There is some more renderFacets but this is enough -->
</cc:implementation>
If I have for example p:selectOneMenu inside the form, without any widgetVar definitions, all will be with same name for widgetVar and this is a problem.
So, I changed this completely and I will transform this composite component to ui:composition and decorate it in my page. In that case widget vars are generated as I want, with different names, because they are in different naming containers.
A widgetVar is in fact used in JavaScript to identify the component. Therefor a widgetVar must be unique in a page. You'll have to declare it yourself.
If you want to create a custom component, as I think might suit you better than ui:define/ui:include, you might want to do something like this:
Say we want to create a component that renders a p:commandButton and a h:outputText with the same value (for whatever reason). You create a XHTML page in directory [deployed-root]/resources/example, named customComponent.xhtm:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsf/composite">
<c:interface>
<c:attribute name="text" required="true" />
</c:interface>
<c:implementation>
<h:outputText value="#{cc.attrs.text}" />
<p:commandButton value="#{cc.attrs.text}" />
</c:implementation>
</html>
Then to use this in another page you'll have to define the namespace xmlns:e="http://java.sun.com/jsf/composite/example", and then you can refer to the custom component like this: <e:customComponent text="some text here"/>.
It should also be noted that it is bad practice to declare forms in custom components. This affects flexibility of use drastically since forms cannot be nested.
PrimeFaces can generate wigetVars so you don't have to.
From the 3.4 User's Guide:
<p:dialog id="dlg">
<!-- contents -->
</p:dialog>
<p:commandButton type="button" value="Show" onclick="#{p:widgetVar('dlg')}.show();"/>
This is designed to work in naming containers, so it should work just fine in composite components, <ui:repeat/>, <h:dataTable/>, etc.

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