How to refer to a bound component in a DataTable with EL? - jsf-2

Using expression language, how can I access a component that is bound and repeated in a datatable?
<h:dataTable value="#{bean.items}" var="item" id="table">
<h:column>
<h:inputText value="#{item.name}" id="name" binding="#{mybinding}"/>
</h:column>
</h:dataTable>
Should I give each binding a generated name with a concatenation of a literal and the row index, for instance ('mybinding_1', 'mybinding_2', and so forth), and if so, how?
Or instead is there a way to get a particuliar element with #{mybinding} plus some kind of brace notation ([])?

There's a misconception going here. There are definitely not physically multiple <h:inputText> components in the component tree. There's only one component whose HTML representation is generated multiple times depending on the current state of the parent table component. You can confirm this by walking through the component tree starting at FacesContext#getViewRoot(), you'll ultimately find only one <h:inputText> component.
So, binding="#{mybinding}" is perfectly fine.
If you're having problems with it, it's caused elsewhere and needs to be solved differently. Only and only if you're using a view build time tag to generate physically multiple components in a loop, such as JSTL <c:forEach>, then there would indeed be physically multiple <h:inputText> components in the component tree and you'd need to bind them to an array or map. But this is currently clearly not the case.

Related

What are the downsides of using binding in order to update a JSF component?

Consider this xhtml piece.
<p:dialog id="consumerDialog"
widgetVar="dealerDialog" modal="true">
<h:panelGroup binding="#{cdContent}">
</h:panelGroup>
</p:dialog>
<p:dialog id="dealerDialog"
widgetVar="dealerDialog" modal="true">
<h:form>
<p:commandButton value="Close"
onclick="PF('dealerDialog').hide()"
update=":#{cdContent.clientId}"/>
</h:form>
</p:dialog>
In the dealerDialog component is a p:commandButton which updates the h:panelGroup component inside the consumerDialog where the id of the updated component is obtained through binding. I sometimes do this to save pains figuring out the actual id of the target component (especially for complex views).
Are there any downsides or risks if I do it this way?
Are there any downsides or risks if I do it this way?
Only if the EL variable represented in binding, which is in your case #{cdContent}, is shared by multiple components in the same view. E.g. when the given code snippet is included multiple times in the same template via <ui:include>, tagfile or composite. Or even when there's a managed bean on that name. It doesn't apply in your case, but it would for sure fail if the binding attribtue references a session scoped bean property.
There are no risks if you make absolutely sure that #{cdContent} is exclusively used by only one component in the entire view.
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?

How do you pass a Managed Bean of different type to a composite for reuse?

I'm creating an inline text editor. I've written the code to edit one single h:ouputText field (h:inputHidden). Works. Thus, I thought I create a composite (widget), that I can call for every field I want to update. Of course, those fields refer to a managed bean in my case, that is the PubController MB.
<composite:interface name="inlineEditor">
<composite:attribute name="attrOfMb" required="true"
type="java.lang.String" />
<composite:attribute name="pubController" required="true" type="com.playground.webapp.controller.PubController"/>
</composite:interface>
Now, I have the following tasks to accomplish:
pass the MB to the composite (done).
in the composite, create the div and the hidden input field with id of the MB attribute.
Challenge where I struggle:
How do I "bind" an attribute of the passed PubController to the hidden input field? #{cc.attrs.pubController.title}? Well, it should not always be the same attribute. The attribute should be chosen by what has been passed in the interface attribute attrOfMb.
In other cases, its not necessariley PubController. Might be another MB. My initial thought was to define the interface type to javax.faces.bean.ManagedBean. On the other hand, how could you then "bind" the passed MB to the input hidden field (respectively vice-versa).
Is there a JSF-Pattern on how you accomplish these things?
You're going in the wrong path as to designing the composite. You should bind a bean property, not a whole bean.
I.e. you should not have
<my:composite bean="#{bean}" />
but you should have
<my:composite value="#{bean.value}" title="#{bean.title}" />
Once you fix that problem, then you can easily reuse it on any backing bean. Please note that this is also the way how standard JSF <h:xxx> components work. If you worry about about "too many" attributes for some unclear reason, then just create a reusable model class which in turn can be a property of the backing bean.
<my:composite data="#{bean.data}" />
This way you can use it further in the composite as #{cc.attrs.data.value}, #{cc.attrs.data.title}, etc.
If you really, really need to bind a whole bean, then I'd question if a tag file or maybe an include file isn't a better solution for whatever functional requirement you've had in mind. A composite component should really represent a component with a single responsibility and a single point of model value binding.
See also:
When to use <ui:include>, tag files, composite components and/or custom components?

OmniFaces o:validateAllOrNone in ui:repeat or h:dataTable

Is it possible to use OmniFaces <o:validateAllOrNone> (which is pretty cool ;)) within an <ui:repeat> or <h:dataTable>?
I need a table with each row having an input field column. You could either fill in none of these values or all of them.
If I put the <o:validateAllOrNone> within the <ui:repeat> or <h:dataTable> and use the id of the input field in components attribute, then the validator also gets triggered, if all fields are empty.
No, that's not possible. The components attribute must refer physically multiple components, not a single component which is rendered multiple times. It can however be used on physically multiple components which are rendered during same iteration round. The <o:validateXxx> multi field validator is not designed to reference a single component which is rendered multiple times. The only OmniFaces validator which does that is <o:validateUniqueColumn>.
If you want to use the <o:validateXxx> multi field validator on dynamic inputs based on a collection, then your best bet is to use JSTL <c:forEach>. It will build physically multiple components.
E.g.
<c:forEach items="#{bean.items}" var="item" varStatus="loop">
<h:inputText id="input_#{loop.index}" value="#{item.value}" />
</c:forEach>
Assuming that there are 3 items, this will dynamically create JSF components with IDs of input_0, input_1 and input_2. Then you can just use <o:validateXxx> as follows (put it outside the loop!)
<o:validateAllOrNone components="input_0 input_1 input_2" />
You can replace the hardcoded string in the above example by an EL expression which returns the desired space separated string of component IDs from a backing bean.
<o:validateAllOrNone components="#{bean.inputIds}" />
An alternative would be to create a <x:validateAllOrNoneColumn> yourself or to post an enhancement request at OmniFaces issue tracker. It would be not exactly trivial to alter the existing <o:validateAllOrNone> that a completely separate component is desired.

JSF 2.0 - how to get the property path of a jsf component?

is there a way to get from a JSF component the property path which is obviously used for updating the model?
I am asking cause we have a concept where the backend validates the whole stuff. Don't ask why but I am not allowed to use JSF build-in validation.
The backend provides ValidationException if for example a property is null but should not be null and the ValidationException contains a list of ValidationInfos containing the full property path for the property the validation info belongs to.
My task is to find a way to map back this info to the corresponding JSF component to be able to show the message for the correct JSF component.
It is allowed for me to register/attach some kind of little helpers to the component to make it easier for mapping back the infos.
My first approach was to write a tag handler and in the tag handler to find out the property path and the root bean. But I am lost there cause we are also using JSF 2.0 components with deferred value expression so I see at the moment a value expression like vor example #{cc.attrs.value} but I am interested in the "caller" expression like for example #{aBean.street} which is obiously the property path for updating the model.
<composite:interface>
<composite:attribute name="value" required="true"/>
</composite:interface>
<composite:implementation>
<h:inputText value="#{cc.attrs.value}" styleClass="#{!component.valid ? 'col2 error' : 'col2'}">
<my-components:registerTagHandler value="#{cc.attrs.value}"/>
</h:inputText>
</composite:implementation>
Maybe there are other approaches or other ideas out there. It would be helpful for me to get some hints/ideas.
Best Regards,
Walter
PS: sorry for my crude english cause I am not a native english speaker.

ui:repeat var attribute not working as expected

Due to the problem with #ViewScoped, I have to use ui:repeat instead of c:foreach in my facelet. However I encounter this problem and I wonder if anyone can suggest a work-around.
<ui:repeat value="#{someBean.idCodes}"
var="led">
<h:outputText id="mailbox-#{led}"
value="#{someBean.getSomeValue(led)}" />
</ui:repeat>
The first problem is that the #{led} reference is the id attribute does NOT get evaluated. All the generated id attributes are simply the value "mailbox-". I need to find specific element instances with document.getElementById() so I need generated id attributes.
The other problem which I can't see a workaround for is that if I wrap the ui:repeat element inside an h:panelGrid element, I end up with a table with one cell in it, rather than one cell for each member of the idCodes collection.
When using c:foreach neither of these problems exist, but use of that tag causes other problems. Any suggestions?
Notice in the javadocs that the type of the id attribute is String, not ValueExpression. That's why your ${led} is not evaluated. You could try to wrap each one in a div or span and set the id of that element to your ${led} based expression.

Resources