1
votes

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);
}
1
I don't see a selectionMode being specified for your datatable. Have you tried adding one?RevanProdigalKnight
I have used the selectionMode in the first column.Rodrigo Souza Mendonça
I have also tried the parameter rowSelectMode, but I did not get success.Rodrigo Souza Mendonça
Could you add the code of mBeanDataLazy model that you use?Seitaridis

1 Answers

1
votes

I have found the problem.

<!-- 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" />

The Ajax events should belong to PrimeFaces library.

When I replace f: by p: in both events, I get the rowKey in DataTable class and consequently the selected row.