JSF h:column tag not evaluating rendered attribute - jsf

I've got a JSF data table that conditionally displays each item based on a Boolean property of the item, as follows:
<h:dataTable value='#{sessionBean.items}' var='item'>
<h:column rendered='#{item.visible}'>
<h:outputText value='#{item.description}'/>
</h:column>
</h:dataTable>
My problem is that the rendered attribute does not seem to be referring to visible property in my item at all. I've put a tracing message in the getter for the property, and can confirm that the getter is not getting called at all. What really puzzles me though, is that the following works:
<h:dataTable value='#{sessionBean.items}' var='item'>
<h:column rendered='true'>
<h:outputText value='visible = #{item.visible}'/>
<h:outputText value='#{item.description}'/>
</h:column>
</h:dataTable>
That is, in this case all items are rendered, and the text "visible = true" or "visible = false" is successfully output for each. It is only in the column rendered attribute that the getter is not working.
Does anyone have any idea what might cause this behaviour, and what I should do to correct it?

Table columns (read: <td> elements which are all in the same column, which thus applies on all rows) cannot be rendered on a per-row basis. That's not really a JSF restriction, but more a HTML restriction. Ask yourself, how should the HTML end up to look like? What should the browser do with all those missing <td> elements on a per-row basis? Right, it makes no sense at all :)
Just move the row-based rendering to the cell contents:
<h:column>
<h:outputText value="#{item.description}" rendered="#{item.visible}"/>
</h:column>
Or make it a bean based rendering if you actually want to hide the whole column altogether:
<h:column rendered="#{sessionBean.visible}">
<h:outputText value="#{item.description}"/>
</h:column>

Related

JSF validation error prevents updating another valid rows of an h:dataTable placed in an h:form

I have an h:dataTable inside of an h:form, where each row has it's own h:commandButton type="submit" action="#{bean.saveChanges(item)}".
f:inputs are declared as required and they also need to match a pattern.
If every input is in the right format, then it works fine.
Otherwise it needs only one input to be wrong and an updating function on a commandButton corresponding to a completely different item in another row seems not to be called, therefore not updated in the database.
Also only the wrong row's validation message is displayed and the changes are maintained in the view by a (backing Spring view scoped) bean, so the user might actually think, that the initial row was indeed updated in the database too.
Is there a way, how to separate individual rows of the h:dataTable, so that the validation messages of another row does not stop other items from being updated by the method of a (Spring/backing) bean?
Use ajax to process/execute only the current row. You can achieve that by explicitly specifying the client IDs of the input components in <f:ajax execute>.
<h:form>
<h:dataTable ...>
<h:column>
<h:inputText id="foo" ... />
</h:column>
<h:column>
<h:inputText id="bar" ... />
</h:column>
<h:column>
<h:inputText id="baz" ... />
</h:column>
<h:column>
<h:commandButton ...>
<f:ajax execute="foo bar baz #this" ... />
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
This won't process the inputs in other rows. Use if necessary <f:ajax render> to update the <h:message(s)> associated with the inputs.
See also:
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
The required on the input cause the Process validation to fail and the render response to be invoked.
A simple solution could be You could remove the required from the input and handle the case in you managed bean. Since the action would move on till Phase 5: Invoke application the valid data can be saved. For all invalid rows highlight the row by having a boolean in you data model.

show details row's datatable

I've got a datatable in a .xhtml page, that shows products of a database.
Let's say that I can only see Name and Code for every row, how can I show more detail of the product in the same page?
Moreover, my product bean is in ViewScope, so i'm not able to show details in another .xhtml page (I've tried many times, but if in case you guys have a solution for this, that's good).
PS: I don't know anything about Javascript yet, so i'd prefer mostly solutions based on jsf and java :)
You mean that you want to display more fields at datatable?
Add more columns..
<h:dataTable value="#{pr.products}" var="p">
<h:column>
<f:facet name="header">Name</f:facet>
#{p.name}
</h:column>
<h:column>
<f:facet name="header">Code</f:facet>
#{p.code}
</h:column>
<h:column>
<f:facet name="header">Price</f:facet>
#{p.price}
</h:column>
........
</h:dataTable>
JSF example: http://www.mkyong.com/jsf2/jsf-2-datatable-example/
If you using primefaces see showcase: http://www.primefaces.org/showcase/ui/data/datatable/basic.xhtml
EDIT
If you want to make a dialog that shows the details of the selected product see at primefaces showcase the "selection" example.

h:dataTable renders rows correctly but does not show cell values while ui:repeat does

I have the following data table.
<h:dataTable value="#{flightReservation.flightList}" var="flight">
<h:column>
<h:outputText value="#{flight.fromPlace}" />
</h:column>
<h:column>
<h:outputText value="#{flight.toPlace}" />
</h:column>
</h:dataTable>
It does not show any data inside the cells, even though the number of rows is equal to the flightList size.
When I replace it by <ui:repeat>, then it shows the data.
<ui:repeat value="#{flightReservation.flightList}" var="value">
<h:outputText value="#{value.fromPlace}" />
<h:outputText value="#{value.toPlace}" />
</ui:repeat>
How is this caused and how can I solve it?
I encountered the same behaviour once and it was simply an issue with the scope of variables:
You are saying, that the number of rows is correct, but the content not displayed. You are naming the variable flight and I assume that a value with this name has been used earlier in your markup or even used as a <ui:param>.
The Datatable is now iterating (internal) and generating the correct amount of rows, but when it tries to access the properties of fligt jsf refers to the earlier declared variable and fails to find the properties fromPlace, toPLace etc.
Try to rename your variable and see if this solves your issue.
The example bellow would produce stringList.size() times yoloyolo even if one would expect the content of the list to be shown. And if the listsource is made out of objects, any instance access on the attributes will fail cause yoloylo is not an object of the expected type.
<ui:param name="foo" value="yoloyolo" />
<h:dataTable value="#{backingBean.stringList}" var="foo">
<h:column>
<f:facet name="header">string</f:facet>
- #{foo}
</h:column>
</h:dataTable>

JSF2 Building Dynamic EL Expressions

I am working on creating a dynamic table using JSTL forEach and a h:dataTable and have all of the controls and potential error message showing nicely, but am now stuck on getting the value set for each of the control. I will need to create (I think) a dynamic EL expression to set the value, but have not been able to get any of my versions to work. I was hoping to build out the expression using c:out, but found out that that tag is not available in JSF2.
So, is it possible to build a dynamic expression in the page?
How can I set the expression in the backing bean if the control hasn't been built yet ?
<h:dataTable id="dtDetails" styleClass="slate_table" value="#{remediationDetail.eventList}" var="dataItem">
<c:forEach items="#{remediationDetail.eventHeaders}" var="key">
<h:column>
<f:facet name="header">#{key.fieldDefinition.fieldConfiguration.customLabel}</f:facet>
<h:inputText value="" id="txtNumber" styleClass="remediation_textbox error_marker" title="#{remediationDetail.errorMessages(dataItem.id, key.fieldDefinition.id)}">
<f:convertNumber maxFractionDigits="0" maxIntegerDigits="19"/>
</h:column>
</c:forEach>
</h:dataTable>
As always, any help or direction is appreciated.
Regards,
Mike
I was not being able to create a Dynamic EL Expression. So, I ended using the index of the c:forEach to help define what values I am looking for. The only catch for this result is that I would be expecting the data that I am about to display to have the same number of positions in the array.
<c:forEach items="#{remediationDetail.eventHeaders}" var="key" varStatus="looper">
<h:column>
<f:facet name="header">#{key.fieldDefinition.fieldConfiguration.customLabel}</f:facet>
<h:inputText id="txtNumber" value="#{dataItem.entityList[looper.index].val}">
<f:convertNumber maxFractionDigits="0" maxIntegerDigits="19"/>
</h:inputText>
</h:column>
</c:forEach>
In my case the following helped to build dynamic EL.
<ui:param name="beanName" value="myBackedBean"/>
<ui:param name="propertyName" value="field1"/>
<ui:param name="nestedPropertyName" value="field1"/>
<p:inputTextarea value="#{sessionScope[beanName][propertyName][nestedPropertyName]}"/>
Inspired of this topic

Group visibility of rich:columns inside rich:datatable

I have a set of columns inside a rich:datatable, those columns are visible based on some preprocessed conditions. An example of what I want to do is this:
<rich:datatable value="tableList" var="list">
<h:panelGroup rendered="#{condition}">
<rich:column>
Component
<rich:column>
<rich:column>
Component
<rich:column>
</h:panelGroup>
<h:panelGroup rendered="#{not condition}">
<rich:column>
Component
</rich:column>
</h:panelGroup>
</rich:datatable>
The problem here is that the panelGroup tag never gets rendered inside the rich:datatable, even when I remove the "rendered" condition. I tried with an a4j:outputPanel and a few others but none worked.
I could remove the panel and put the condition in each column but that would be the last thing I would do.
Why is not working? Regards.
In fact, I am pretty sure that the <rich:dataTable> will ignore any direct children that are not a UIColumn or Column object (I just had a look on org.richfaces.component.ColumnsIterator, used by UIDataTable).
In others words, your <h:panelGroup> will simply be ignored by the <rich:dataTable>, not matter when the rendered attribute value is.
To solve your problem, I see three solutions:
Put a rendered attribute on each <rich:column>;
Use the <rich:columnGroup> component;
Define two <rich:dataTable>, one display when #{condition} is evaluated to true, the other one when it is false.

Resources