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

