I am trying to get the selected row in a PrimeFaces DataTable, but when the event is called on my bean, the value of the object is null. I have read some articles about this. It seems to be a problem related to the rowKey parameter. When I use the DataTable component without using a composite, I can get the object value normally. As far as I understand, when I use the composite, by default the view is of type Object. This means that the rowKey parameter cannot be assigned to "#{item.id}" because the type Object does not has an attribute called id. After doing a deeper investigation, I found out that the problem starts on method queueEvent on DataTable class.
@Override
public void queueEvent(FacesEvent event) {
FacesContext context = getFacesContext();
if(isRequestSource(context) && event instanceof AjaxBehaviorEvent) {
setRowIndex(-1);
Map<String,String> params = context.getExternalContext().getRequestParameterMap();
String eventName = params.get(Constants.RequestParams.PARTIAL_BEHAVIOR_EVENT_PARAM);
String clientId = this.getClientId(context);
FacesEvent wrapperEvent = null;
AjaxBehaviorEvent behaviorEvent = (AjaxBehaviorEvent) event;
if(eventName.equals("rowSelect")||eventName.equals("rowSelectRadio")||eventName.equals("contextMenu")
||eventName.equals("rowSelectCheckbox")||eventName.equals("rowDblselect")) {
String rowKey = params.get(clientId + "_instantSelectedRowKey");
wrapperEvent = new SelectEvent(this, behaviorEvent.getBehavior(), this.getRowData(rowKey));
}
else if(eventName.equals("rowUnselect")||eventName.equals("rowUnselectCheckbox")) {
String rowKey = params.get(clientId + "_instantUnselectedRowKey");
wrapperEvent = new UnselectEvent(this, behaviorEvent.getBehavior(), this.getRowData(rowKey));
}
else if(eventName.equals("page")) {
int rows = this.getRowsToRender();
int first = Integer.parseInt(params.get(clientId + "_first"));
int page = rows > 0 ? (int) (first / rows) : 0;
wrapperEvent = new PageEvent(this, behaviorEvent.getBehavior(), page);
}
else if(eventName.equals("sort")) {
SortOrder order;
UIColumn sortColumn;
if(isMultiSort()) {
String[] sortDirs = params.get(clientId + "_sortDir").split(",");
String[] sortKeys = params.get(clientId + "_sortKey").split(",");
order = SortOrder.valueOf(sortDirs[sortDirs.length - 1]);
sortColumn = findColumn(sortKeys[sortKeys.length - 1]);
}
else {
order = SortOrder.valueOf(params.get(clientId + "_sortDir"));
sortColumn = findColumn(params.get(clientId + "_sortKey"));
}
wrapperEvent = new SortEvent(this, behaviorEvent.getBehavior(), sortColumn, order);
}
else if(eventName.equals("filter")) {
wrapperEvent = new FilterEvent(this, behaviorEvent.getBehavior(), getFilteredValue(), getFilters());
}
else if(eventName.equals("rowEdit")||eventName.equals("rowEditCancel")||eventName.equals("rowEditInit")) {
int rowIndex = Integer.parseInt(params.get(clientId + "_rowEditIndex"));
setRowIndex(rowIndex);
wrapperEvent = new RowEditEvent(this, behaviorEvent.getBehavior(), this.getRowData());
}
else if(eventName.equals("colResize")) {
String columnId = params.get(clientId + "_columnId");
int width = Integer.parseInt(params.get(clientId + "_width"));
int height = Integer.parseInt(params.get(clientId + "_height"));
wrapperEvent = new ColumnResizeEvent(this, behaviorEvent.getBehavior(), width, height, findColumn(columnId));
}
else if(eventName.equals("toggleSelect")) {
boolean checked = Boolean.valueOf(params.get(clientId + "_checked"));
wrapperEvent = new ToggleSelectEvent(this, behaviorEvent.getBehavior(), checked);
}
else if(eventName.equals("colReorder")) {
wrapperEvent = behaviorEvent;
}
else if(eventName.equals("rowToggle")) {
boolean expansion = params.containsKey(clientId + "_rowExpansion");
Visibility visibility = expansion ? Visibility.VISIBLE : Visibility.HIDDEN;
String rowIndex = expansion ? params.get(clientId + "_expandedRowIndex") : params.get(clientId + "_collapsedRowIndex");
setRowIndex(Integer.parseInt(rowIndex));
wrapperEvent = new ToggleEvent(this, behaviorEvent.getBehavior(), visibility, getRowData());
}
else if(eventName.equals("cellEdit")) {
String[] cellInfo = params.get(clientId + "_cellInfo").split(",");
int rowIndex = Integer.parseInt(cellInfo[0]);
int cellIndex = Integer.parseInt(cellInfo[1]);
int i = -1;
UIColumn column = null;
for(UIColumn col : this.getColumns()) {
if(col.isRendered()) {
i++;
if(i == cellIndex) {
column = col;
break;
}
}
}
wrapperEvent = new CellEditEvent(this, behaviorEvent.getBehavior(), rowIndex, column);
}
wrapperEvent.setPhaseId(event.getPhaseId());
super.queueEvent(wrapperEvent);
}
else {
super.queueEvent(event);
}
}
In the following line the rowKey value is not found:
String rowKey = params.get(clientId + "_instantSelectedRowKey");
Instead of this, I have the id of the selected lines in a key called selection (clientId + "_selection"). The line above works when I use the DataTable directly, without using the cc:implementation.
Does someone has an alternative to get the selected row when I have to use a DataTable in a composite?
This is a part of the composite that I use to display data.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<cc:attribute name="mBeanOnRowSelect" required="true"
method-signature="void action(javax.faces.event.AjaxBehaviorEvent)" />
<cc:attribute name="mBeanOnRowUnselect" required="true"
method-signature="void action(javax.faces.event.AjaxBehaviorEvent)" />
<cc:implementation>
<p:dataTable id="grid" var="item" value="#{cc.attrs.mBeanDataLazy}"
paginator="true" rows="#{cc.attrs.rows}" paginatorPosition="bottom"
currentPageReportTemplate="({currentPage} #{msgs.label_of} {totalPages})"
paginatorTemplate="{CurrentPageReport} {FirstPageLink}
{PreviousPageLink} {PageLinks} {NextPageLink}
{LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="#{cc.attrs.rowsPerPage}" lazy="true"
rowKey="#{item.id}"
selection="#{cc.attrs.selectionBean[cc.attrs.selectionProperty]}"
emptyMessage="#{msgs['label_grid_emptyMessage']}"
filteredValue="#{cc.attrs.mBeanFilteredItems}"
widgetVar="#{cc.attrs.itemsGrid}" resizableColumns="true"
filterEvent="enter" rendered="#{cc.attrs.renderGrid}"
scrollable="#{cc.attrs.gridScrollable}" scrollWidth="1200">
<!-- Header -->
<cc:insertFacet name="header" />
<!-- Colunas do grid -->
<p:column selectionMode="#{cc.attrs.gridSelection}" width="20"
resizable="false" />
<!-- Marca a linha do grid -->
<f:ajax event="rowSelect" listener="#{cc.attrs.mBeanOnRowSelect}"
render="gridButtons grid" />
<!-- Desmarca a linha do grid -->
<f:ajax event="rowUnselect" listener="#{cc.attrs.mBeanOnRowUnselect}"
render="gridButtons grid" />
<!-- Colunas do grid -->
<cc:insertChildren />
</p:dataTable>
</cc:implementation>
</html>
This is the bean method called when a row is selected.
public void onRowSelect(AjaxBehaviorEvent event)
throws AbortProcessingException {
super.onRowSelect(event);
}
selectionMode
being specified for your datatable. Have you tried adding one? – RevanProdigalKnightmBeanDataLazy
model that you use? – Seitaridis