Dynamic columns with richfaces 4 - jsf-2

I need dynamic number of columns. Richfaces supplies it with <rich:columns> in richfaces 3.3.3-final but for Richfaces 4 they seem to recommend <c:forEach>.
c:forEach
I can't get it to work properly.Since I can't depend on the var from the datatable I can't figure out how to feed <c:forEach> with the correct list of columns. (Each row has their own values but headers are the same)
Basically the data I want to display is a list with rows of x size, each row has a list of column values with y size. But how can have <c:forEach> tell the backing bean what row it's at so I can feed the correct columns?
ui/a4j:repeat
I dont want to reinvent the wheel because I need frozen columns and many other features. Creating the table html this way and use jQuery for other features have been considered. However this would be hopeless to maintain and to much work.
I also looked at constructing it from the backing bean creating children dynamically but I don't like that at all. This would have to be the last resort.
Using: Tomcat 7, servlet 3.0, JSF 2.1x - Mojarra, Richfaces 4.x
Update
Okay so I'm getting some results finally. However my headers don't show. The values show perfectly but not the headers. Some problem doing them with iteration or something perhaps?
<rich:dataTable value="#{controller.rows}"
var="row">
<c:forEach items="#{controller.columns}" var="column">
<rd:column id="name" width="250">
<f:facet name="header">
<h:outputText value="#{row.myArrayList[column].header}" />
</f:facet>
<h:inputText value="#{row.myArrayList[column].value}" disabled="#{row.myArrayList[column].open}"/>
</rd:column>
</c:forEach>
</rich:dataTable>

The <c:forEach> is indeed best what you can get. The <ui/a4j:repeat> won't work as that runs during view render time while the UIData component really needs UIColumn children, not UIRepeat children.
In order to get the <c:forEach> to work, you need to supply it a list/map of all property names (and in case of a map maybe also header labels). Here's a concrete kickoff example assuming that Item has properties id, name and value and that #{bean.itemPropertyNames} returns a List<String> with exactly those property names.
<rich:dataTable value="#{bean.items}" var="item">
<c:forEach items="#{bean.itemPropertyNames}" var="itemPropertyName">
<rich:column>
#{item[itemPropertyName]}
</rich:column>
</c:forEach>
</rich:dataTable>
If you need to show column headers as well, then best is to have a Map<String, String> where the key represents the property name and the value represents the header value.
<rich:dataTable value="#{bean.items}" var="item">
<c:forEach items="#{bean.itemProperties}" var="itemProperty">
<rich:column>
<f:facet name="header">#{itemProperty.value}</f:facet>
#{item[itemProperty.key]}
</rich:column>
</c:forEach>
</rich:dataTable>
Either way, the only disadvantage is that the #{bean} of <c:forEach items> can in this construct not be a view scoped one. It would be recreated on every request, unless you turn off partial state saving. It needs to be a request scoped one (or session or application). Note that it does not necessarily need to be the same bean as the one in <rich:dataTable value>.
See also:
Dynamically generate h:column based on list of hashmaps

Related

c:forEach not working on ace:dataTable var [duplicate]

In my application I want to display a <h:dataTable> with managed bean properties. Currently this table is created from a List<Folder>. Now I want to change the Folder to something more dynamic. That's because I don't want to change the Folder class if I decide to add another field later. I would just have to add another entry in the Map<String, Object> instead of introducing a new field in Folder.
So, is it possible to bind a List<Map<String, Object>> to the <h:dataTable>?
Is it possible to bind a List of HashMaps to the jsf component h:dataTable?
That's only possible if you generate the necessary <h:column> tags with a view build time tag such as JSTL <c:forEach>.
Here's a concrete kickoff example, assuming that your environment supports EL 2.2:
<h:dataTable value="#{bean.listOfMaps}" var="map">
<c:forEach items="#{bean.listOfMaps[0].keySet().toArray()}" var="key">
<h:column>
#{map[key]}
</h:column>
</c:forEach>
</h:dataTable>
(if your environment doesn't support EL 2.2, you'd need to provide another getter which returns the map key set as a String[] or List<String>; also keep in mind that a HashMap is by nature unordered, you might want to use LinkedHashMap instead to maintain insertion order)
When you're using Mojarra version older than 2.1.18, the disadvantage is that the #{bean} has to be request scoped (not view scoped). Or at least, the <c:forEach items> should refer a request scoped bean. A view scoped bean would otherwise be recreated on every single HTTP request as the <c:forEach> runs during view build time, when the view scope isn't availabe yet. If you absolutely need a view scoped bean for the <h:dataTable>, then you can always create a separate request scoped bean exclusively for <c:forEach items>. The solution would be to upgrade to Mojarra 2.1.18 or newer. For some background information, see also JSTL in JSF2 Facelets... makes sense?
JSF component libraries such as PrimeFaces may offer a <x:columns> tag which makes this more easy, such as <p:dataTable> with <p:columns>.
<p:dataTable value="#{bean.listOfMaps}" var="map">
<p:columns value="#{bean.listOfMaps[0].keySet().toArray()}" var="key">
#{map[key]}
</p:columns>
</p:dataTable>

How to hide components by selecting a new value on h:selectOneMenu?

I have a page with a h:selectOneMenu, and I want to hide a dataTable when I choose a new value on the h:selectOneMenu while some bean attribute values update. I'm trying diferent things, and I'm able to hide the dataTable by reloading the page. I have tried this using some JavaScript code, on onsomething attributes. In that case, those bean attribute values disapear although I use t:saveState (and I also need the view scope for the bean).
Here is a little example to clarify this:
<h:selectOneMenu id="list" value="#{Bean.id}">
<f:selectItems value="#{Bean.List}" var="element" itemLabel="#{element.name}" itemValue="#{element.id}"/>
<t:saveState value="#{Bean.id}"/>
<f:ajax listener="#{Bean.populateBean}" render=":form:period" event="change"/>
</h:selectOneMenu>
<h:selectOneMenu id="period" value="#{Bean.period}">
<f:selectItems value="#{Bean.listaPeriod}" var="period" itemLabel="#{period[1]}" itemValue="#{period[0]}"/>
<t:saveState value="#{Bean.period}"/>
</h:selectOneMenu>
<h:commandButton id="search" action="#{Bean.doSearch}"></h:commandButton>
<t:dataTable id="data" value="#{Bean.configList}" rendered="#{Bean.search}"
<t:column>
...
</t:dataTable>
And Bean.doSearch changes Bean.search to true. How can I hide the dataTable when I choose a new value on h:selectOneMenu id="list"?
EDIT:
In short, the search button renders the table, and I would want to hide that table when I just choose a new value on the "list" dropdown without reloading the page. Now, the <f:ajax> is used only to rerender the "period" dropdown value.
Thanks in advance!
Your question is hardly understandable, but if you want to kick the datatable out of your view on ajax request triggered by your dropdown, you need to enclose it in a component that's always present in the view so that HSF would know what to rerender when ajax call successfully finishes:
<h:panelGroup id="rerender">
<t:dataTable rendered="#{bean.condition}" ...>
....
</t:dataTable>
<h:panelGroup>
Of course, to get it working you should specify id of the component to be rerendered:
<h:selectOneMenu ...>
...
<f:ajax listener="#{bean.populate}" render="rerender" />
</h:selectOneMenu>
Note that if both dropdown and datatable components belong to the same form, it's not necessary to specify absolute id of the latter's parent. Also note that specifying event is redundant, as it already defaults to the right one. Finally, as you're on JSF 2.x, using save state is not necessary, just bind the values of your form data to a view scoped bean.
The last thing to note is the fact that you fail to conform to the Java Naming Conventions, the thing you should correct as soon as possible.

primefaces3.0 datatable selection and value property

I have upgraded my project from Primefaces 2.2 to 3.0
I am facing problems in Datatable. I have a Datatable whose values i am populating through a list and selected rows are kept in array
<p:dataTable id="datavalues" value="#{bean.list}"
var="o" paginator="true" rows="10"
selection="#{bean.selected1}"
rowKey="#{o.property1}" >
now i want the selected rows to be used in another Datatable and on that Datatable i have used values as "#{bean.selected1}" and selection as #{bean.selected2} as i also need the selected values from this Table.
<p:dataTable id="table4" var="o" value="#{bean.selected1}"
rows="10"
selection="#{bean.selected2}"
rowKey="#{o.property2}"
>
The Exception I got is :
[Lcom.packagedirectory.beans.beanHelper; cannot be cast to java.util.Collection
list, selected1, selected2 are all properties of beanHelper Class.
This code was perfectly working on 2.2 Has it something to do with That value is also an array and selection is also an array.
In Primefaces 2.2 the selection would have updated its bean value automatically, however this was probably not desirable for every situation, so in 3.0 they changed it so that for an ajax postback to occur you need to place a <p:ajax> tag with a rowSelect event within the dataTable.
<p:dataTable id="table1" ... >
<p:ajax event="rowSelect" update="formid:table1 formid:table2" oncomplete="dlg.show()" />
...
</p:dataTable>
<p:dataTable id="table2" ... >
...
</p:dataTable>
Selections of the first dataTable should trigger the server postback and partial page update of your second dataTable.
I think you should try to add selectionMode="multiple" in your 1st <p:dataTable> and selectionMode="single" in your 2nd <p:dataTable>.

JSF2 CommandButton Action request params

<h:commandButton value="Add Order" action="#{orderBasket.addItems(param['orderItemId'])}"/>
I can't get the above to work...when you click on the button the param seems to get set to null. Is there a way around this?
Is there another way of passing the URL params into the action method? I'm using Spring EL resolver which limits my ability to pass in the parameters into beans as I'm not using faces-config.
First, I think you could use JSF better, a lot of problems would be much simpler. It looks that you are using JSF as a request/response framework, like Struts. JSF is an object oriented component framework, you should use it this way to get the best of it.
I'll try to solve your problem, but I'm missing some information on what you are doing.
If you have a list of books that you can order, let's say they are displayed in a datatable (you could use ui:repeat instead) :
<h:dataTable value="#{bookController.books}" var="book">
<h:column>
<h:outputText value="#{book.title}" />
</h:column>
<h:column>
<h:commandButton value="Add Order" action="#{orderBasket.addItems(book)}" />
</h:column>
</h:dataTable>
In orderBasket backing bean, you simply take a Book (or whatever) as parameter. You don't need to handle the request/response cycle, certainly not in your views.
You can use f:ajax tag if you need to display that in your shopping cart immediately.
Let me know if you need more explanation (backing beans source or else).

Icefaces rowselector

Could someone give me a nice and clean example of how to use the Icefaces 2.0 rowselector? My plan is to use it as a component, so I can reuse it for all kinds of lists.
<ice:dataTable id="table" value="#{cc.attrs.list}" var="record">
<ice:column>
<ice:rowSelector rendered="#{cc.attrs.select == 1}" value="#{cc.attrs.selectMethod}"
selectedClass="tableRowSelected" mouseOverClass="tableRowMouseOver"
immediate="false" selectionListener="#{cc.attrs.selectMethod}" />
<f:facet name="header">
<ice:outputText value="#{record.idDesc}"></ice:outputText>
</f:facet>
<ice:outputText value="#{record.id}"></ice:outputText>
</ice:column>
..
</ice:dataTable>
As you may see, I'm not sure how Im going to handle the value="???" and the selectionListener="???". I'm not sure how to implement it in the bean.
It would be great if I can separate the bean and the component methods into two differnet classes. Whenever I need a rowSelector, for some List object in some Bean, I simply add the Component object to present bean.
Maybe to many things at 1 time, if so, sorry for that =)
B.R
Problem solved! =)
Made a list and a listener.

Resources