PrimeFaces Datatable always selecting the first element

497 views Asked by At

Every time I select some of the elements of my p:datatable it always returns the first one, always.

I have this following piece of code that is used on my screen, in which the detailEntity is referenced in the table as a row of the same.

Tab Lots

        <sgv:detailCrud
            scrollable="true"
            scrollHeight="350"
            updateClass="lotChangeListener, .crudButtons"
            controller="#{productLotsController}"
            btnDetailDeleteLabel="#{productByLotsController.inNewMode or productLotsController.inNewMode ? productsBundle.deleteLabel : productsBundle.inactivateLabel}"
            withDelete="#{productLotsController.showEntity and productLotsController.deletableEntity}"
            disabled="#{not (productByLotsController.byLots and not productsController.inViewMode)}">
            <p:column headerText="#{productsBundle.productLotsBarcode}">
                <h:outputText
                    value="#{detailEntity.barcode}"
                    converter="barcodeConverter" />
            </p:column>
            <p:column headerText="#{productsBundle.productLotsNumber}">
                <h:outputText value="#{detailEntity.number}" />
            </p:column>
            <p:column
                headerText="#{productsBundle.productLotsExpiration}"
                rendered="#{productByLotsController.perishable}">
                <h:outputText value="#{detailEntity.expirationData.expiration}">
                    <f:convertDateTime
                        type="both"
                        locale="#{currentUserConfigController.locale}" />
                </h:outputText>
            </p:column>
            <p:column
                headerText="#{productsBundle.fieldLabelStockAvailable}"
                rendered="#{productsController.hasStockByLocation()}">
                <h:outputText value="#{productLotsController.getStockByLocation(detailEntity).totalizedStockData.availableAmount}" />
            </p:column>
            <p:column
                headerText="#{productsBundle.fieldLabelStockReserved}"
                rendered="#{productsController.hasStockByLocation()}">
                <h:outputText value="#{productLotsController.getStockByLocation(detailEntity).totalizedStockData.reservedAmount}" />
            </p:column>
            //THIS BUTTON ONLY SELECT THE FIRST ROW OF MY TABLE, IT'S BROKEN.
            <p:column
                width="35"
                rendered="#{productByLotsController.byLots}">
                <p:commandButton
                    id="btnPrintPaperLot"
                    title="#{productsBundle.btnPrintBarCode}"
                    process="@this"
                    actionListener="#{printerSelectorController.onPrint()}"
                    icon="fa fa-print">
                    <f:setPropertyActionListener
                        value="PAPER"
                        target="#{printerSelectorController.type}" />
                    <f:setPropertyActionListener
                        value="#{productLotsController.getTypePrintedProductLot(detailEntity)}"
                        target="#{printerSelectorController.value}" />
                </p:commandButton>
            </p:column>

As you can see, I have a custom component that I created called sgv:detailCrud. He is responsible for owning the CRUD architecture of my services, being able to delete, create or view details of a line. (VIDEO DETAILS)

Details CRUD Component

<!DOCTYPE html>
<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:composite="http://xmlns.jcp.org/jsf/composite"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:p="http://primefaces.org/ui"
    xmlns:of="http://omnifaces.org/functions">
<head>
<title>Details CRUD Component</title>
</head>
<body>
    <composite:interface>
        <composite:attribute name="style" />
        <composite:attribute name="styleClass" />
        <composite:attribute name="listStyle" />
        <composite:attribute name="listStyleClass" />
        <composite:attribute name="datailStyle" />
        <composite:attribute name="datailStyleClass" />
        <composite:attribute
            name="controller"
            required="true"
            type="eprecise.sgv.server.core.CrudController" />
        <composite:attribute
            name="disabled"
            default="false" />
        <composite:attribute
            name="withInsert"
            default="true" />
        <composite:attribute
            name="scrollable"
            default="false" />
        <composite:attribute
            name="scrollHeight"
            default="400" />
        <composite:attribute
            name="withDelete"
            default="true" />
        <composite:attribute
            name="withUpdate"
            default="true" />
        <composite:attribute
            name="emptyMessage"
            default="#{detailCrudBundle.emptyMessage}" />
        <composite:attribute
            name="btnNewLabel"
            default="#{detailCrudBundle.btnNewLabel}" />
        <composite:attribute
            name="btnDetailDeleteLabel"
            default="#{detailCrudBundle.detailBtnDelete}" />
        <composite:attribute
            name="btnDetailSaveLabel"
            default="#{detailCrudBundle.detailBtnSave}" />
        <!-- Parametro de classe Css listener de update -->
        <composite:attribute
            name="updateClass"
            default="#{cc.id}ChangeListener" />
        <composite:facet name="list" />
        <composite:facet name="details" />
    </composite:interface>
    <composite:implementation>
        <p:outputPanel
            id="#{cc.id}"
            styleClass="#{cc.id}ChangeListener">
            <p:panel
                styleClass="Wrapper"
                rendered="#{not cc.attrs.controller.showEntity}">
                <f:facet name="header">
                    <composite:renderFacet name="title" />
                    <p:commandLink
                        id="btnNew"
                        styleClass="Fright"
                        update="@(.#{cc.attrs.updateClass},.#{cc.id}ChangeListener)"
                        process="@this"
                        icon="fa fa-plus-circle"
                        disabled="#{cc.attrs.disabled}"
                        rendered="#{cc.attrs.withInsert}"
                        action="#{cc.attrs.controller.onBtnNovoClick()}">
                        <i class="fa fa-plus-circle Fs23 White"></i>
                    </p:commandLink>
                    <p:tooltip
                        for="btnNew"
                        showDelay="500"
                        value="#{cc.attrs.btnNewLabel}" />
                    <div class="clearfix"></div>
                </f:facet>
                <p:dataTable
                    id="list"
                    selectionMode="single"
                    scrollable="#{cc.attrs.scrollable}"
                    scrollHeight="#{cc.attrs.scrollHeight}"
                    selection="#{cc.attrs.controller.entity}"
                    emptyMessage="#{cc.attrs.emptyMessage}"
                    value="#{cc.attrs.controller.dataModel}"
                    reflow="true"
                    var="detailEntity"
                    rowKey="#{detailEntity.id}">
                    <f:attribute
                        name="styleClass"
                        value="#{cc.attrs.listStyleClass} #{cc.attrs.styleClass}" />
                    <p:ajax
                        event="rowSelect"
                        listener="#{cc.attrs.controller.onEntityClick()}"
                        process="@this"
                        update="@(.#{cc.attrs.updateClass}, .#{cc.id}ChangeListener, .formConfirmDialog)"
                        onstart="crudController.blockTable();"
                        onsuccess="crudController.unblockTable();" />
                    <composite:insertChildren />
                </p:dataTable>
            </p:panel>
            <p:panel
                id="detailCrudPanel"
                styleClass="disableFluidForButtons detailForm"
                rendered="#{cc.attrs.controller.showEntity}">
                <f:attribute
                    name="styleClass"
                    value="#{cc.attrs.datailsStyleClass} #{cc.attrs.styleClass} detailForm" />
                <f:facet name="header">
                    <p:commandButton
                        id="btnSaveDetail_#{cc.id}"
                        styleClass="saveBtn RaisedButton Fright WidAuto"
                        update="@(.#{cc.attrs.updateClass}, .#{cc.id}ChangeListener)"
                        process="@(.detailForm)"
                        value="#{cc.attrs.btnDetailSaveLabel}"
                        icon="fa fa-save"
                        rendered="#{cc.attrs.withUpdate and not cc.attrs.disabled}"
                        action="#{cc.attrs.controller.onBtnSalvarClick()}" />
                    <p:commandButton
                        action="#{cc.attrs.controller.onBtnDeleteClick()}"
                        icon="fa fa-trash-o"
                        styleClass="deleteBtn Fright WidAuto"
                        value="#{cc.attrs.btnDetailDeleteLabel}"
                        disabled="#{cc.attrs.disabled}"
                        process="@this"
                        rendered="#{cc.attrs.withDelete and (cc.attrs.controller.inEditMode or cc.attrs.controller.inViewMode)}"
                        update="@(.#{cc.attrs.updateClass}, .#{cc.id}ChangeListener)">
                    </p:commandButton>
                    <p:commandButton
                        update="@(.#{cc.attrs.updateClass}, .#{cc.id}ChangeListener)"
                        process="@this"
                        styleClass="cancelBtn Fright WidAuto"
                        icon="fa fa-ban"
                        value="#{detailCrudBundle.detailBtnCancel}"
                        rendered="#{not cc.attrs.disabled}"
                        action="#{cc.attrs.controller.onBtnCancelarClick()}" />
                    <p:commandButton
                        update="@(.#{cc.attrs.updateClass}, .#{cc.id}ChangeListener)"
                        process="@this"
                        styleClass="RedButton RaisedButton"
                        icon="fa fa-arrow-left WidAuto"
                        value="#{detailCrudBundle.detailBtnBack}"
                        rendered="#{cc.attrs.disabled}"
                        action="#{cc.attrs.controller.onBtnCancelarClick()}" />
                    <p:defaultCommand
                        target="btnSaveDetail_#{cc.id}"
                        scope="detailCrudPanel" />
                </f:facet>
                <composite:renderFacet name="details" />
            </p:panel>
        </p:outputPanel>
    </composite:implementation>
</body>
</html>

Another detail is that I can do these crud operations on the rows of the table without any problem, that is, hitting the index. However, I have this problem of always selecting the first row when I click my button to print a lot variation, it's like it doesn't obey the crud architecture for some bizarre reason...

I believe this problem is only for the view, but for the sake of conscience I will post the code of the two controllers of this button here too, follow the thread.

Method that should take the selected entity in the table and assemble it from the String Builder

public String getTypePrintedProductLot(ProductLot selectedLot) {
        if (selectedLot != null && selectedLot instanceof ProductLot) {
            final Optional<ProductLabelSetting> optional = this.productLabelSettingsRepository.listActives().stream().findFirst();

            if (optional.isPresent()) {
                final StringBuilder builder = new StringBuilder();
                final SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
                final HashMap<String, Object> params = new HashMap<String, Object>();

                final Logger log = LoggerFactory.getLogger(ProductLotsController.class);
                log.warn("********** SELECTED LOT NUMBER IN TABLE **********\n");
                log.warn(selectedLot.getNumber());
                log.warn("********** SELECTED LOT NUMBER IN TABLE **********\n");

                params.put("product", selectedLot);

                final ProductLot lot = selectedLot;
                params.put("lot", lot);
                if (lot.getExpirationData() instanceof PerishableExpirationData) {
                    params.put("lotExpiration", sdf.format(lot.getExpirationData().getExpiration()));
                } else {
                    params.put("lotExpiration", "Não Perecível");
                }
                params.put("login", this.currentUser.getLogin().toUpperCase());
                params.put("enterprise", this.currentEnterprise.getName().toUpperCase());
                builder.append(optional.get().parser(params));

                return builder.toString();
            }
        }

        return null;
    }

Controller that receives the values ​​from the String Builder and prints the variation according to this information

package eprecise.sgv.server.core.printers;

import java.io.Serializable;
import java.util.Optional;

import javax.inject.Inject;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

import eprecise.sgv.server.products.ProductLotsController;
import org.apache.commons.lang3.StringUtils;

import eprecise.sgv.server.core.ViewController;
import eprecise.sgv.server.core.auth.Current;
import eprecise.sgv.server.core.util.FacesMessageUtil;
import eprecise.sgv.server.devicesHub.remoteHw.RemoteHwChannel;
import eprecise.sgv.server.devicesHub.remoteHw.printers.RemoteHwPrinter;
import eprecise.sgv.server.devicesHub.remoteHw.printers.RemoteHwPrintersRepository;
import eprecise.sgv.server.users.User;
import org.primefaces.PrimeFaces;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


@ViewController
public class PrinterSelectorController implements Serializable {

    private enum PrintType {
                            COMMON,
                            PAPER,
                            COUPON
    }

    private static final long serialVersionUID = 1L;

    private final RemoteHwPrintersRepository repository;

    private final User user;

    private final RemoteHwChannel remoteHwChannel;

    private String id;

    private String value;

    private String type;

    private @NotNull @Min(1) int amount = 1;

    private Boolean withAmount = false;

    private RemoteHwPrinter printer;

    public PrinterSelectorController() {
        this.repository = null;
        this.user = null;
        this.remoteHwChannel = null;
    }

    @Inject
    public PrinterSelectorController(RemoteHwPrintersRepository repository, @Current User user, RemoteHwChannel remoteHwChannel) {
        this.repository = repository;
        this.user = user;
        this.remoteHwChannel = remoteHwChannel;
    }

    public void onPrint() {
        if (!this.withAmount) {
            switch (PrintType.valueOf(this.type.toUpperCase())) {
            case COMMON:
                break;
            case PAPER:
                if (this.user.hasDefaultPrinterPaper()) {
                    if (this.print(this.user.getConfigurations().getDefaultPrinters().getPaper())) {
                        FacesMessageUtil.addInfoMessage("Etiqueta impressa com sucesso.");
                        break;
                    }
                } else {
                    this.showDialog();
                }
                break;
            case COUPON:
                break;
            default:
                this.showDialog();
                break;
            }
        } else {
            this.showDialog();
        }
    }

    public void onPrint(RemoteHwPrinter printer) {
        if (printer != null) {
            switch (PrintType.valueOf(this.type.toUpperCase())) {
            case COMMON:
                break;
            case PAPER:
                if (this.print(printer)) {
                    FacesMessageUtil.addInfoMessage("Etiqueta impressa com sucesso.");
                }
                break;
            case COUPON:
                break;
            }
        } else {
            FacesMessageUtil.addErrorMessage("Nenhuma impressora selecionada.");
        }
    }

    public void onPrintSelect() {
        this.onPrint(this.printer);
    }

    private boolean print(DefaultPrinter defaultPrinter) {
        final Optional<RemoteHwPrinter> optional = this.repository.findById(defaultPrinter.getId());

        if (optional.isPresent()) {
            return this.print(optional.get());
        }

        this.showDialog();
        return false;
    }

    private boolean print(RemoteHwPrinter printer) {
        if (StringUtils.isNotBlank(this.value)) {
            final StringBuilder builder = new StringBuilder();
            for (int i = 1; i <= this.amount; i++) {
                builder.append(this.value);
            }
            this.remoteHwChannel.sendPrint(printer, builder.toString());

            this.clearFields();

            return true;
        }

        FacesMessageUtil.addErrorMessage("Modelo a ser impresso está vazio.");
        return false;
    }

    private void clearFields() {
        this.amount = 1;
        this.printer = null;
        this.id = null;
        this.value = null;
        this.type = null;
    }

    private void showDialog() {

        final Logger log = LoggerFactory.getLogger(PrinterSelectorController.class);
        log.warn("********* VALUE OF SELECTED LOT *********\n");
        log.warn(this.value);
        log.warn("********* VALUE OF SELECTED LOT *********\n");

        PrimeFaces.current().executeScript(
                new StringBuilder("PF('").append(this.id).append("_").append("listPrintersDialogJs").append("').show();").toString());
    }

    public String getId() {
        return this.id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getValue() {
        return this.value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getType() {
        return this.type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public int getAmount() {
        return this.amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }

    public RemoteHwPrinter getPrinter() {
        if (StringUtils.isEmpty(this.type)) {
            return null;
        }
        switch (PrintType.valueOf(this.type.toUpperCase())) {
        case COMMON:
            break;
        case PAPER:
            if (this.user.hasDefaultPrinterPaper()) {
                final Optional<RemoteHwPrinter> optional = this.repository
                        .findById(this.user.getConfigurations().getDefaultPrinters().getPaper().getId());
                if (optional.isPresent()) {
                    this.printer = optional.get();
                }
            }
            break;
        case COUPON:
            break;
        }

        return this.printer;
    }

    public void setPrinter(RemoteHwPrinter printer) {
        this.printer = printer;
    }

    public Boolean getWithAmount() {
        return this.withAmount;
    }

    public void setWithAmount(Boolean withAmount) {
        this.withAmount = withAmount;
    }
}
Details

I'm using Java 8 with primefaces in version 7

Some images

Broken primefaces table Details of correct index selected (LOT NUMBER 3)

Video

https://youtu.be/kw_xhQxrV-M

0

There are 0 answers