Is it possible to do dynamic column ordering on a p:dataTable without using p:columns? - jsf

I'm trying to dynamically display the columns of a p:dataTable: the server dictates which columns are displayed and in which order. It doesn't look like I can set a dynamic order using the regular p:column tag so I'm stuck using the p:columns tag. The problems with the p:columns tag are:
1) The example in the showcase shows it working with String data, where you can map a column name to a field and then use an expression language map to retrieve the data (like a pseudo-getter)
http://www.primefaces.org/showcase/ui/data/datatable/columns.xhtml
If I have different data types though, then I'm probably stuck with a bunch of panels with render attributes based on the type of the data (display Strings one way, display User objects another way, etc).
Example:
<p:dataTable value="#{myBean.rows}" var="row">
<p:columns value="#{myBean.columns}" var="column">
<f:facet name="header">
<h:outputText value="#{column.header}" />
</f:facet>
<!-- The content of the cell is dynamic based on the type of the field -->
<!-- display a String field -->
<h:outputText rendered="#{myBean.isStringType(column.header)}"
value="#{row[column.property]}"/>
<!-- display a Person field -->
<h:outputText rendered="#{myBean.isPersonType(column.header)}"
value="#{row[column.property].name}, #{row[column.property].email}"/>
</p:columns>
</p:dataTable>
2) p:columns only supports a single sortFunction/filterFunction for all columns. Since these columns all have different types of data, they will require many different sorting and filtering methods
A p:column easily allows for the display of different data types as well as the sorting/filtering of the data. The only thing it can't do is have a dynamic order.
Unless I'm missing something? Is there a way to get this to work with p:column ? Or is there an elegant way to have p:columns handle all of this?

It doesn't look like I can set a dynamic order using the regular p:column tag so I'm stuck using the p:columns tag.
If the #{myBean.columns} columns model is constant during at least the view scope, then you'd better use <c:forEach><p:column><c:choose>. It's faster than <p:columns>+rendered, and allows more dynamic freedom as you can declare every <p:column> individually depending on the type instead of having only one <p:columns> whose state changes every iteration round.
<p:dataTable value="#{myBean.rows}" var="row">
<c:forEach items="#{myBean.columns}" var="column">
<c:choose>
<c:when test="#{column.type eq 'STRING'}">
<p:column sortBy="#{row[column.property]}" filterBy="#{row[column.property]}">
#{row[column.property]}
</p:column>
</c:when>
<c:when test="#{column.type eq 'PERSON'}">
<p:column sortBy="#{row[column.property].name}" filterBy="#{row[column.property].name}">
#{row[column.property].name}, #{row[column.property].email}
</p:column>
</c:when>
...
</c:choose>
</c:forEach>
</p:dataTable>
See also:
JSTL in JSF2 Facelets... makes sense?
How to create dynamic JSF form fields

Related

Flipped over dataTable primefaces

Is it possible to flip datatable in primefaces, in order to have headers in the left not in the top?
I have following table:
<p:dataTable value="#{rolesMgmt.listOfMapsRoles}" var="map" id = "dataTable">
<p:columns value="#{rolesMgmt.columns}" var="column">
<f:facet name="header">
<h:outputText value="#{column.header}" />
</f:facet>
<h:outputText value="#{map[column.property]}" />
</p:columns>
</p:dataTable>
As you see, I have a lot of headers and 2-3 rows and I need to flip this table
No this is not possible by using some attribute on the p:dataTable itself. For this to be achieved you need to transpose your model. Maybe you can achieve something by manipulating the responsiveness. But if you have lots of columns AND lots of rows, maybe you should think of just displaying a 'summary' in a datatable and have a details view.
Or use a p:datagrid (showcase) where you can sort of free-format your records or a plain ui:repeat? Since you do not seem to need sorting/filtering etc in this case. The p:datatable seems overkill to me now
It's not possible to flip the table.
Why don't you take a look to the ColumnToggler?
You can temporarly reduce the width of the table and then, on demand, add other columns.

selection issue p:dataTable with selectionmode set to multiple nested in p:dataGrid

I'm working on a PrimeFaces project, where I choose to use a p:DataTable inside a p:DataGrid. The DataTable has the selectionMode attribute set to "multiple". I have a button on the page and when I click on it, I want to get all the selected checkboxes inside the various generated tables. All the checkboxes bring the same type of information (they are in different tables because of an information grouping scheme I use in the project).
Since I have multiple DataTables in the final rendered page, how can I get the selected checkboxes? I tried using the selection="#{myBean.selectedOptions}" attribute of the DataTable, but it seems to get just one of the generated tables' selected options (aparently the first one). What can I do to get the selected options of all tables generated by the p:DataGrid? Javascript? Is there any point I'm missing in the DataTable behavior?
(Well.. I don`t know whether I was able to make myself clear enough - English is not my native language).
[edited]
More information:
The number o DataTables generated is variable
I tried using the jsf visit method to traverse the user interface component view as shown here, looking for all checkboxes inside the DataGrid, but it couldn't find any of the checkboxes (I printed out to the console all the elements found). I think it's because the checkboxes are encapsulated in DataTable component. This made me think about not using the selectionMode="multiple" and, instead, manually add the checkboxes and a hidden input element for each one so I can find the checkboxes (or the "input hidden") using the visit method. The sad part of this aproach is that I'd have to stop using some good stuff of the DataTable selectionMode="multiple" feature, like hilighting the row if the corresponding checkbox is checked, and the ready to use "check all" checkbox it automatically put in the header of the ckeckboxes column.
I tried using a nested List in the selection attribute, but it didn't work. The main idea was using something like selection="#{bean.myListOfLists.get(t.counter)}". The "counter" variable is taken from the very object that is used to fulfill the current row of the DataTable (represented by the t variable in the attribute var="t"). The DataTable seems to not accept this approach. It doesn`t fulfill the nested lists.
I tried using the above approch with a modification: instead of a list of lists, a build a new class "B" and made a list of B (selection="#{bean.myListOf_B_Objects.get(t.counter).listInsideBObject}"). The result is simliar to the last approach: none of the lists inside the B objects were fulfilled.
Below there is a simplified view of what I did (more similar to the last case, but it's just to get the big picture)
<p:dataGrid var="gridCellContent"
value="#{myBean.dataGridContent}"
layout="grid" id="id01" columns="3"">
<p:dataTable var="something"
value="#{gridCellContent.listOfSomething}"
rowKey="#{something.id}"
selection="#{myBean.listOf_B_Objects.get(gridCellContent.counter).listInside_B_Object}">
<p:column selectionMode="multiple" />
<p:column>
<h:outputText value="#{something.sometext}" />
</p:column>
</p:dataTable>
<f:facet name="footer">
<p:commandButton id="btnSave" value="Save"
actionListener="#{myBean.btnSave}"/>
</f:facet>
</p:dataGrid>
[edited 2] Following #JaqenH'ghar's sugestion I tried out the modifications below, which unfortunately still din't work:
<p:dataGrid var="gridCellContent"
value="#{myBean.dataGridContent}"
layout="grid" id="id01" columns="3"
rowIndexVar="count">
<p:dataTable var="something"
value="#{gridCellContent.listOfSomething}"
rowKey="#{something.id}"
selection="#{myBean.listOfLists.get(count)}">
<p:column selectionMode="multiple" />
<p:column>
<h:outputText value="#{something.sometext}" />
</p:column>
</p:dataTable>
<f:facet name="footer">
<p:commandButton id="btnSave" value="Save"
actionListener="#{myBean.btnSave}"/>
</f:facet>
</p:dataGrid>
And for myBean:
#ManagedBean
public class MyBean {
...
private List<List<Something>> listOfLists = new ArrayList<List<Something>>();
public List<List<Something>> getListOfLists(){
this.listOfLists.add(new ArrayList<Something>());
return this.listOfLists;
}
public void setListOfLists(List<Something> listOfSomething) {
this.listOfLists.add(listOfSomething);
}
...
}

Saving data from multiple inputtext boxes created by a loop in jsf

Basically, I have an input text box that I want to submit for each item in the array. The code below is cut down to the relevant portions
<c:forEach items="${mybean.mats}" var="mat">
<p:dataTable var="datarow" value="#{mybean.getDatarows(mat.itemId)}" rowIndexVar="row">
<p:column>
<p:inputText value="#{bean.amt}" />
</p:column>
</p:dataTable>
</p:panel>
<p:commandButton value="Confirm" action="#{mybean.runSubmit}" process="#this" />
</c:forEach>
From what I know, each individual item needs to have its own variable name to save the data in each input text box. I know the method I'm currently using is wrong, so is there another way to save all the data? Perhaps in an array or something?
First, mixing the JSTL c:foreach with a datatable is not recommended. Use ui:repeat instead.
Second, your p:dataTable value has to reference a collection that exists during the lifetime of the backing bean. It looks to me like the call to #{mybean.getDatarows(mat.itemId)} generates a list of items dynamically. That's going to be a problem since your backing bean will need to call the getDatarows when the values are re-applied to the bean on your ajax call runSubmit to save the values. In this case, you will need to save the dynamically created list to the backing bean so that the same collection will match up exactly to the collection used to produce the html.
For example, suppose your backing bean contains the property List<List<Mat>> mats, where the Mat class contains a single property 'dataId'. Then, your EL could be:
<h:form id="input-form">
<ui:repeat id="mats-repeat" value="#{mats}" var="mat">
<p:dataTable id="mat-table" value="#{mat}" var="dataObj">
<p:column>
<p:inputText id="dataId" value="#{dataObj.dataId}" />
</p:column>
</p:dataTable>
</ui:repeat>
</h:form>
Since the form, repeat, and dataTable components are naming containers, they ensure that any child components are named uniquely. In this case, the first input mat element would be rendered as:
<input id="input-form:mats-repeat:0:mat-table:0:dataId" ...

Filtering issues (no change in contents) in datatable primefaces 3.5, sorting works

Primefaces 3.5 doesn't seem to filter data at all from the datatable, oddly enough it somehow reorders them as I type, so, there must be some AJAX calls firing, but obviously not the right ones.
<h:panelGroup id="table-wrapper-component">
<prime:dataTable
rendered="#{artifactSelectionBackingBean.visibleComps}"
value="#{artifactSelectionBackingBean.components}"
var="tagInfoObject" emptyMessage="No tags found with given criteria"
filteredValue="#{artifactSelectionBackingBean.filteredComponents}">
<prime:ajax event="filter" global="false" />
<prime:column sortBy="#{tagInfoObject.tagId}"
headerText="Identifier" filterMatchMode="contains" filterBy = "#{tagInfoObject.tagId}">
<h:outputText value="#{tagInfoObject.tagId}" />
</prime:column>
<prime:column sortBy="#{tagInfoObject.type.tagTypeId}"
headerText="Tag Identifier" filterMatchMode="contains" filterBy ="#{tagInfoObject.type.tagTypeId}">
<h:outputText value="#{tagInfoObject.type.tagTypeId}" />
</prime:column>
<prime:column sortBy="#{tagInfoObject.title}" headerText="Title" filterMatchMode="contains" filterBy="#{tagInfoObject.title}">
<h:outputText value="#{tagInfoObject.title}" />
</prime:column>
<prime:column filterBy="#{tagInfoObject.description}"
filterMatchMode="contains" sortBy="#{tagInfoObject.description}"
styleClass="wrap" headerText="Component Description">
<h:outputText value="#{tagInfoObject.description}" />
</prime:column>
</prime:dataTable>
</h:panelGroup>
Any help is appreciated! All the Beans and method calls exist and return the appropriate data, just that the filtering doesn't seem to work at all.
Also, note that sorting functions properly only filtering does not!
The issue was that you always need to wrap any filtering/sorting attributes in a data table with an h:form tag. This is not explicitly specified in the documentation of PrimeFaces, however, it is in the showcase here. I wrapped the whole thing in form tags.
So, don't forget to wrap your data tables in a form if you want any type of interaction provided by primefaces.
Your managed Bean Code will do a lot of good
Post your managed bean code.
May be you have not set the value for artifactSelectionBackingBean.filteredComponents in the managed bean

input binding in ui:repeat in jsf

i am using facelets jsf 2.0 with primefaces 3.0.M2 component library.
i am trying to achieve dynamic numbers of rows including iput fields that are filled when a datatable selection occurs.
whenever a selection is made the dynamic rows generated correctly with input fields but after the first selection for following selections dynamic row count changes correctly but the input fields does not update and keeps showing inputs from the first selection.
here is how i iterate list in facelet;
<ui:repeat value="#{goalEntranceBean.selectedCard.parameterList}" var="prmBean" >
<li><h:outputText value="#{prmBean.lookUp.value}"/></li>
<li>
<h:outputText value="Weight:"/>
<p:inputText id="wx" required="true" value="#{prmBean.weight}">
</p:inputText>
<h:outputText value="Percent:"/>
<p:inputText required="true" value="#{prmBean.percent}">
</p:inputText>
</li>
</ui:repeat>
my bean where i get the list of cards and set the selectedCard with rowSelect event in datatable.
#ManagedBean(name = "goalEntranceBean")
#ViewScoped
public class GoalEntranceAction implements Serializable {
private List<ScoreCard> personalCards = new ArrayList<ScoreCard>();
private ScoreCard selectedCard = new ScoreCard();
......
}
when i checked in debug mode i can see the true list but in screen the elements does not change.
This is a common problem (gets asked every couple of days). To make long story short, inputs inside ui:repeat do not work, period.
It is a problem with JSF, a long standing, famous one. Maybe it will be fixed. Maybe not, it seems that no one really cares (I mean - an input? in a... ui:repeat? such crazy scenario!).
A quick-fix is to use a h:dataTable, possibly ungodly abused with css to make it look like a list. A long-fix is to use some iterator from a different library. Primefaces has an element that should work that renders an unordered list.
thanks for your replies. Sorry for forget sharing the solution.
As i mentioned above i have primefaces datatable.
On row selection event i render datatable and want to update the cells of that datatable.
USING p:inputtext easily solved my problem. Now i can change the data on screen and i can see the values after update operation on screen. I don't understand the reason but it works.
<p:dataTable var="orgPrmBean"
value="#{scoreCardOperationsBean.selectedCard.orgParameterList}"
emptyMessage="#{labels.norecord}"
rowKey="#{orgPrmBean.id}"
>
<p:columnGroup type="header">
<p:row>
<p:column headerText="Parameters" colspan="3" style="text-align:left;width:480;"/>
</p:row>
</p:columnGroup>
<p:column style="text-align:left;width:200px;">
<h:outputText value="#{orgPrmBean.info}"/>
</p:column>
<p:column style="text-align:left;width:180px;">
<p:inputText value="#{orgPrmBean.weight}"
rendered="#{scoreCardOperationsBean.selectedCard.goalEdit}">
<f:convertNumber maxFractionDigits="0"/>
</p:inputText>
</p:column>
</p:dataTable>
It IS possible to make it work, but the solution is to bind the inputs to a backing bean, and update the values of the controls in the backing bean via listeners (using the new value received in the argument). Obviously this isn't a good solution if you have a complex form, as you need to add a listener/control in the backing bean for each control in the page, but it's practical if you just have one or two inputs.

Resources