I'm using datatable with multiple selection and pagination, when I select a row and go to another page and then return to the page I was the row I've selected is not selected anymore. I'm using primefaces 3.5, mojarra, jboss 7.1, my bean is viewScoped. Below is my code:
<p:dataTable id="boxList" var="box" value="#{protocolBean.boxModel}" paginator="true" rows="10" paginatorPosition="bottom"
selection="#{protocolBean.selectedBoxes}">
<f:facet name="header">
#{label['boxes']}
</f:facet>
<p:column selectionMode="multiple" style="width:4%" />
<p:column>
<h:outputText value="#{box.code}"/>
</p:column>
<p:column filterBy="#{box.selected}" filterOptions="#{protocolBean.selectedOptions}" filterMatchMode="exact">
<h:outputText value="#{box.selected}"/>
</p:column>
</p:dataTable>
Model:
public class BoxModel extends ListDataModel<Box> implements SelectableDataModel<Box> {
public BoxModel() {
}
public BoxModel(List<Box> boxes) {
super(boxes);
}
#Override
public Object getRowKey(Box box) {
return box.getId();
}
#SuppressWarnings("unchecked")
#Override
public Box getRowData(String rowKey) {
List<Box> boxes = (List<Box>) getWrappedData();
for(Box b : boxes) {
if(b.getId().equals(rowKey))
return b;
}
return null;
}
}
I discovered what was happening, the problem is with my model class, in method getRowData I'm comparing a long (b.getId) with a String (rowKey) this way the method always return null and will never know who is selected.
Related
I would like a button in a Primefaces DataTable row to show a dialog showing more information about the object in the row. When I click anywhere in the row not in the button, the row is selected. However, when I press the button, the row is not selected. How may I make the row that the button is in the selected row?
This example from the Primefaces showcase sets selectedCar in the backing bean and displays a dialog containing data from the row on clicking a button in the row but leaves the row unselected:
<p:dataTable id="basicDT" var="car" value="#{dtSelectionView.cars1}">
<f:facet name="header">
Basic
</f:facet>
<p:column headerText="Id">
<h:outputText value="#{car.id}" />
</p:column>
<p:column headerText="Year">
<h:outputText value="#{car.year}" />
</p:column>
<p:column headerText="Brand">
<h:outputText value="#{car.brand}" />
</p:column>
<p:column headerText="Color">
<h:outputText value="#{car.color}" />
</p:column>
<p:column style="width:32px;text-align: center">
<p:commandButton update=":form:carDetail" oncomplete="PF('carDialog').show()" icon="ui-icon-search" title="View">
<f:setPropertyActionListener value="#{car}" target="#{dtSelectionView.selectedCar}" />
</p:commandButton>
</p:column>
</p:dataTable>
.. and this example from the same page selects a row in the table and the backing bean but an subsequent button click to display a dialog:
<p:dataTable id="singleDT" var="car" value="#{dtSelectionView.cars2}" selectionMode="single" selection="#{dtSelectionView.selectedCar}" rowKey="#{car.id}">
<f:facet name="header">
Single with Row Click
</f:facet>
<p:column headerText="Id">
<h:outputText value="#{car.id}" />
</p:column>
<p:column headerText="Year">
<h:outputText value="#{car.year}" />
</p:column>
<p:column headerText="Brand">
<h:outputText value="#{car.brand}" />
</p:column>
<p:column headerText="Color">
<h:outputText value="#{car.color}" />
</p:column>
<f:facet name="footer">
<p:commandButton process="singleDT" update=":form:carDetail" icon="ui-icon-search" value="View" oncomplete="PF('carDialog').show()" />
</f:facet>
</p:dataTable>
I'm looking for a graceful solution where you can click any of multiple buttons in a row and select the row at the same time. Here's a use case where multiple buttons are useful - the data for the row contains two richtext fields of arbitrary size which are not easily shown in the table:
Use the var value of the primefaces dataTable attribute, to create a commandLink (or button) inside each row of the dataTable:
If the commandLink is clicked, an actionListener is invoked and sets the rows object as the selectedElement inside the dataTableDialog bean.
Once the ajax request as finished successfully, the update attribute of the commandLink forces the dialog to request the current data from the bean.
Now the JavaScript code of the oncomplete attribute shows up the dialog.
Take a look at the actionListener of the commandLink.
The rows object is stored inside member variable selectedElement. The data of this selected element is shown by the dialog.
Here you've got a nearly complete example:
<h:form id="form">
<p:dialog widgetVar="dlg" modal="true" id="dialog">
<h:outputText value="#{dataTableDialog.selectedElement.key} / #{dataTableDialog.selectedElement.val}" />
</p:dialog>
<p:dataTable
var="cur"
tableStyle="width: auto !important;"
value="#{dataTableDialog.elements}">
<p:column>
<h:outputText value="#{cur.key}" />
</p:column>
<p:column>
<h:outputText value="#{cur.val}" />
</p:column>
<p:column>
<p:commandLink
value="Read more ..."
actionListener="#{dataTableDialog.setSelectedElement(cur)}"
update="form:dialog"
oncomplete="PF('dlg').show()" />
</p:column>
</p:dataTable>
</h:form>
The bean:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
#javax.inject.Named
#javax.enterprise.context.SessionScoped
public class DataTableDialog implements Serializable {
private List<Data> elements;
private Data selectedElement;
#PostConstruct
public void init() {
elements = new ArrayList<>();
elements.add(new Data("Elem 1 Key", "Elem 1 Value"));
elements.add(new Data("Elem 2 Key", "Elem 2 Value"));
}
public List<Data> getElements() {
return elements;
}
public Data getSelectedElement() {
return selectedElement;
}
public void setSelectedElement(Data selectedElement) {
this.selectedElement = selectedElement;
}
}
The data class:
public class Data implements Serializable {
private String key, val; // +getter/+setter
public Data(String key, String value) {
this.key = key;
this.value = value;
}
}
Inspired by the primefaces show case for dataTable Selection:
if it is an option to ommit the button, this example opens a dialog on row click, including row selection.
add an ID to your DataModel
add the attributes selection, selectionMode and rowKey to the dataTable
insert <p:ajax ... /> tag inside dataTable to show the dialog on rowSelectEvent
The facelet:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<h:form id="form">
<p:dialog
widgetVar="elementDialog" modal="true">
<p:outputPanel id="elementDetail">
<p:panelGrid
columns="2"
rendered="#{not empty bean.selectedElement}"
columnClasses="label,value">
<h:outputText value="Key: #{bean.selectedElement.key}" />
<h:outputText value="Val: #{bean.selectedElement.val}" />
</p:panelGrid>
</p:outputPanel>
</p:dialog>
<p:dataTable
var="element"
value="#{bean.elements}"
selection="#{bean.selectedElement}"
selectionMode="single"
rowKey="#{element.id}"
tableStyle="width: auto !important;">
<p:ajax event="rowSelect" oncomplete="PF('elementDialog').show();" />
<p:column headerText="Key">#{element.key}"</p:column>
<p:column headerText="Val">#{element.val}"</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
<p:dataTable
var="element"
value="#{bean.elements}"
selection="#{bean.selectedElement}"
selectionMode="single"
rowKey="#{element.id}"
tableStyle="width: auto !important;">
<p:ajax
event="rowSelect"
oncomplete="PF('elementDialog').show();" />
...
</p:dataTable>
The Data class:
public class Data implements Serializable {
private int id; // + getter/setter
private String key, val; // + getter/setter
public Data(int id, String key, String value) {
super();
this.setId(id);
this.key = key;
this.value = value;
}
}
The bean:
public class Bean implements Serializable {
private List<Data> elements; // + getter
private Data selectedElement; // + getter/setter
#PostConstruct
public void init() {
elements = new ArrayList<>();
elements.add(new Data(0, "Elem 1 Key", "Elem 1 Value"));
elements.add(new Data(1, "Elem 2 Key", "Elem 2 Value"));
}
}
Hopefully this example leads you to archive your goal ... ;)
I have a dataTable with dynamic Columns.
So I use primefaces 5.3 and jsf 2.2
Here is code :
<h:form id="form1">
<p:dataTable var="etudiant" widgetVar="etdTable" paginator="true" rows="10"
rowsPerPageTemplate="5,10,15" value="#{etudiantController.etudiants}"
lazy="false" emptyMessage="Aucune etudiant trouvé"
filteredValue="#{etudiantController.filteredEtudiants}">
<p:column filterBy="#{etudiant.nomEtudiant}" filterMatchMode="exact">
<f:facet name="header">
<h:outputText value="Nom" />
</f:facet>
<h:outputText value="#{etudiant.nomEtudiant}" />
</p:column>
[...]
Bean :
private List<Etudiant> etudiants;
private List<Etudiant> filteredEtudiants;
public List<Etudiant> getEtudiants() {
return etudiantService.getAllEtudiants();
}
public List<Etudiant> getFilteredEtudiants() {
return this.filteredEtudiants;
}
public void setFilteredEtudiants(List<Etudiant> filteredEtudiants) {
this.filteredEtudiants = filteredEtudiants;
}
getAllEtudiants() load all students.
Exception :
java.lang.NullPointerException
at org.primefaces.component.datatable.feature.FilterFeature.filter(FilterFeature.java:150)
at org.primefaces.component.datatable.feature.FilterFeature.encode(FilterFeature.java:117)
at org.primefaces.component.datatable.DataTableRenderer.encodeEnd(DataTableRenderer.java:78)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:924)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1863) [...]
java.lang.IllegalStateException: CDATA tags may not nest
at com.sun.faces.renderkit.html_basic.HtmlResponseWriter.startCDATA(HtmlResponseWriter.java:681) at javax.faces.context.ResponseWriterWrapper.startCDATA(ResponseWriterWrapper.java:179)[...]
something is wrong here??
I'm ot sure but did you try to inicialize the list?
try this:
private List<Etudiant> filteredEtudiants = new ArrayList<>();
when a p:dataTable loop an Object List, it is very easy to use SortBy method in a p:column by use the Object's attribute. like this:
<p:dataTable var="o" value="#{bean.theObjectList}">
<p:column headerText="herderText" sortBy="#{o.objectAttribute1}">
<h:outputLabel value="#{o.objectAttribute1}" />
</p:column>
</p:dataTable>
public class Bean {
private List<TheObject> objectList;
public class TheObject {
private String objectAttribute1;
...
}
...
}
click button like this:
but if I loop a Primitive List which not like Object has some attributes, how can I SortBy it in p:column by click button?
<p:dataTable var="o" value="#{bean.stringList}">
<p:column headerText="herderText" sortBy="?">
<h:outputLabel value="#{o}" />
</p:column>
</p:dataTable>
public class Bean {
private List<String> stringList;
...
}
I am getting a null selected row when I press the showDialog command button
I can't see what is my problem
This is my first form:
<h:form id="firstForm">
<p:commandButton action="#{testBB.showDialog}" id="showDialog"
update=":secondForm" value="#{msg['show.dialog']}" />
</h:form>
This is my second form:
<h:form id="secondForm">
<p:dataTable id="testDatatable"
rendered="#{not empty testBB.list}"
rowKey="#{order.orderNumber}"
selection="#{testBB.selectedRow}"
selectionMode="single"
sortBy="customerName" value="#{testBB.list}" var="order">
<p:column headerText="#{msg['order.number']}">
<h:outputText value="#{order.orderNumber}" />
</p:column>
<p:column headerText="#{msg['total.value']}">
<h:outputText value="#{order.totalValue}" />
</p:column>
</p:dataTable>
</h:form>
My backing bean:
#ManagedBean
#ViewScoped
public class TestBB implements Serializable {
private List<Order> list;
private Order selectedRow;
public void showOrder() {
try {
System.out.println(selectedRow);
} catch (Exception exception) {
}
}
}
And my DTO:
public class Order implements Serializable {
private int orderNumber;
private double totalValue;
public void showOrder() {
try {
System.out.println(selectedRow);
} catch (Exception exception) {
}
}
/** Getters and setters */
}
What is wrong in my code?
Put
<p:ajax event="rowSelect" />
<p:ajax event="rowUnselect" />
inside your datatable for selection/unselection to happen as soon as click happens.
If you need selection only on button click use 'process' like this
<p:commandButton process=":secondForm:testDatatable" update=":secondForm"/>
You need to update the model on rowSelection. This can be done using a <p:ajax event="rowSelect" />. Here is how I think your Datatable should look like:
<p:dataTable id="testDatatable"
rendered="#{not empty testBB.list}"
rowKey="#{order.orderNumber}"
selection="#{testBB.selectedRow}"
selectionMode="single"
sortBy="customerName" value="#{testBB.list}" var="order">
<p:ajax event="rowSelect" />
<p:column headerText="#{msg['order.number']}">
<h:outputText value="#{order.orderNumber}" />
</p:column>
<p:column headerText="#{msg['total.value']}">
<h:outputText value="#{order.totalValue}" />
</p:column>
</p:dataTable>
A good example can be found here (Primefaces Demo).
As Kerem Baydogan suggested you have to include process attribute with your data table id in your command button.
If you are not including process attribute then no components will be processed in the component tree and no modal values will be updated hence you are getting selection as null.
I feel there is no need of updating data table if you are not changing its state.
In my application I am using ViewScoped Bean and it does not show selected row when a row is selected in primefaces datatable. But if I changed the Bean to a SessionScoped Bean then it shows the selected row perfectly.
my code is like below.
<h:form id="form">
<p:growl id="msgs" showDetail="true" />
<p:dataTable var="pMData" rowIndexVar="rowIndex" value="# {managedBean.dataModel}" selectionMode="single" paginator="true" rows="100"
widgetVar="pMTable" emptyMessage="No Records Found." filteredValue="#{managedBean.filteredRecords}" selection="#{managedBean.selectedRecord}" rowKey="#{pMData.cellid}">
<p:ajax event="rowSelect" listener="#{managedBean.onRowSelect}"
update=":form:display :form:msgs" oncomplete="moreviewDialog.show()" />
<p:ajax event="rowUnselect" listener="#{managedBean.onRowUnselect}" update=":form:msgs"/>
<p:column headerText="Cell Name" filterBy="#{pMData.cellid}" filterStyle="display:none" >
<h:outputText value="#{pMData.modifiedCellID}" />
</p:column>
</p:dataTable>
<p:dialog header="History Data" widgetVar="moreviewDialog" resizable="false" id="moreviewDlg"
showEffect="fade" hideEffect="explode" modal="true">
<h:panelGrid id="display" columns="2" cellpadding="4" style="margin:0 auto;">
<p:lineChart id="category" value="# {managedBean.createCategoryModel(managedBean.selectedRecord.cellid)}" legendPosition="e"
title="NodeB Throughput(kbit/s)" minY="0" maxY="5000" style="height:300px;margin-top:20px"/>
</h:panelGrid>
</p:dialog>
</h:form>
and my managedBean CDI is like this.
#Named(value = "managedBean")
#ViewScoped
public class ManagedBean implements Serializable {
public void setSelectedRecord(PMData selectedRecord1){
this.selectedRecord=selectedRecord1;
}
public PMData getSelectedRecord(){
return selectedRecord;
}
public void onRowSelect(SelectEvent event) {
FacesMessage msg = new FacesMessage("NodeB Selected", String.valueOf(((PMData) event.getObject()).getCellid()));
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public void onRowUnselect(UnselectEvent event) {
FacesMessage msg = new FacesMessage("Row Unselected",((PMData) event.getObject()).getCellid());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public PMDataModel getDataModel() {
return dataModel;
}
public CartesianChartModel createCategoryModel(String key) { .....}
public List<PMData> getFilteredRecords() {
return filteredRecords;
}
public void setFilteredRecords(List<PMData> filteredRecords) {
// System.out.println("came ");
this.filteredRecords = filteredRecords;
}
}
and PMData and PMDataModel classes are working normally. Can someone help me to select the row while still using viewscoped bean.
I think I found the answer. the error is with the dialogbox. I put dynamic=true in dialogbox. Now working perfectly.