jsfprimefacesprimefaces-extensions

pe:codeScanner event called multiple times with multiple instances


I have two fields I want to fill using data scanned from a barcode however it seems like when I use two codescanners, the event gets called twice and both fields fill up with the same scanned data which is not what I want.

Here is my code:

            </h:form>
            <p:growl id="growl" showDetail="true" showSummary="true" globalOnly="false">
                <p:autoUpdate/>
            </p:growl>
            <h:form id="form">
                <div class="ui-fluid mb-4">
                    <div class="card border-none">
                        <p:tooltip/>

                        <h:form>
                            <p:messages id="messages" showDetail="true" closable="true" escape="false">
                                <p:autoUpdate/>
                            </p:messages>
                        </h:form>
                    </div>

                    <div class="card mb-4">
                        <p:dataTable id="dt-scannedPo" var="po" value="#{registerView.delivery.deliveryPurchaseOrders}">
                            <p:column headerText="PO Number">
                                <h:outputText value="#{po.purchaseOrder.poNumber}"/>
                            </p:column>
                            <p:column headerText="Invoice Number">
                                <h:outputText value="#{po.invoiceNumber}"/>
                            </p:column>
                        </p:dataTable>
                        <p:commandButton value="Submit Deliveries" oncomplete="PF('submitDeliveriesDialog').show()"
                                         process="@this"/>
                    </div>

                    <p:confirmDialog widgetVar="submitDeliveriesDialog" showEffect="fade" width="300"
                                     message="Submit #{registerView.delivery.deliveryPurchaseOrders.size()} deliveries?"
                                     header="Confirm"
                                     severity="warn">
                        <p:commandButton value="Yes" icon="pi pi-check" actionListener="#{registerView.addDeliveries}"
                                         process="@this" oncomplete="PF('submitDeliveriesDialog').hide()"/>
                        <p:commandButton value="No" type="button" styleClass="ui-button-secondary" icon="pi pi-times"
                                         onclick="PF('submitDeliveriesDialog').hide()"/>
                    </p:confirmDialog>

                    <div class="card border-none">
                        <div class="p-field p-grid">
                            <label for="name" class="p-col-12 p-2 p-md-2 p-mb-md-0 pl-0">Name</label>
                            <div class="p-col-12 p-md-10">
                                <p:inputText id="name" type="text" value="#{registerView.driverName}"/>
                            </div>
                        </div>
                        <div class="p-field p-grid">
                            <label for="contactNo" class="p-col-12 p-2 p-md-2 p-mb-md-0 pl-0">Contact Number (SG only)</label>
                            <div class="p-col-12 p-md-10">
                                <p:inputText id="contactNo" type="number" value="#{registerView.driverNumber}"
                                             required="true" requiredMessage="Contact Number is required"/>
                            </div>
                        </div>
                        <div class="p-field p-grid">
                            <label for="vehicleNo" class="p-col-12 p-2 p-md-2 p-mb-md-0 pl-0">Vehicle Number</label>
                            <div class="p-col-12 p-md-10">
                                <p:inputText id="vehicleNo" type="text" value="#{registerView.driverLicensePlate}"
                                             required="true" requiredMessage="License plate is required"/>
                            </div>
                        </div>
                        <div class="p-field p-grid">
                            <label for="poNumber" class="p-col-12 p-2 p-md-2 p-mb-md-0 pl-0">PO Number</label>
                            <div class="p-col-12 p-md-10">
                                <div class="ui-inputgroup">
                                    <p:inputText id="poNumber" type="text" value="#{registerView.poNumber}" required="true"
                                                 requiredMessage="PO number is required"/>
                                    <p:commandButton icon="fa fa-camera" styleClass="ui-button-success" pt:data-tooltip="Upload Image for OCR" action="#{ocr.detect()}"/>
                                    <p:commandButton id="poBtn" icon="fa fa-qrcode" styleClass="ui-button-danger" 
                                                     pt:data-tooltip="Scan QR Code/Barcode" 
                                                     onclick="PF('poBarcodeDialog').show()"
                                                     immediate="true"/>
                                </div>
                            </div>
                        </div>
                        <div class="p-field p-grid mb-4">
                            <label for="invoiceNumber" class="p-col-12 p-2 p-md-2 p-mb-md-0 pl-0">Invoice Number</label>
                            <div class="p-col-12 p-md-10">
                                <div class="ui-inputgroup">
                                    <p:inputText id="invoiceNumber" type="text" value="#{registerView.invoiceNumber}"/>
                                    <p:commandButton icon="fa fa-camera" styleClass="ui-button-success" pt:data-tooltip="Upload Image for OCR" action="#{ocr.detect()}"/>
                                    <p:commandButton id="invBtn" icon="fa fa-qrcode" styleClass="ui-button-danger" 
                                                     pt:data-tooltip="Scan QR Code/Barcode" 
                                                     onclick="PF('invBarcodeDialog').show()"
                                                     immediate="true"/>
                                </div>
                            </div>
                        </div>
                        <p:commandButton update="@form" value="Add to delivery list"
                                         action="#{registerView.addPurchaseOrderToDelivery}"/>
                    </div>
                </div>
            </h:form>
            <!--Barcode Dialog for PO-->
            <p:dialog header="Scan Barcode/QR Code" widgetVar="poBarcodeDialog" showEffect="fade" modal="true">
                <div class="p-grid">
                    <pe:codeScanner for="form:poNumber" id="poScanner">
                        <p:ajax event="codeScanned" listener="#{registerView.onPOCodeScanned}"/>
                    </pe:codeScanner>
                </div>
            </p:dialog>

            <!--Barcode Dialog for Invoice-->
            <p:dialog header="Scan Barcode/QR Code" widgetVar="invBarcodeDialog" showEffect="fade" modal="true">
                <div class="p-grid">
                    <pe:codeScanner for="form:invoiceNumber" id="invScanner">
                        <p:ajax event="codeScanned" listener="#{registerView.onInvCodeScanned}"/>
                    </pe:codeScanner>
                </div>
            </p:dialog>
public void onPOCodeScanned(final SelectEvent<Code> event) {
        final Code code = event.getObject();
        logger.info("Code scanned: " + code.getValue());
        logger.info("Prev Code scanned: " + poNumber);
        poNumber = code.getValue();
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Code scanned: ", code.getValue()));
        PrimeFaces.current().ajax().update("form:growl");
    }

    public void onInvCodeScanned(final SelectEvent<Code> event) {
        final Code code = event.getObject();
        logger.info("Code scanned: " + code.getValue());
        logger.info("Prev Code scanned: " + invoiceNumber);
        invoiceNumber = code.getValue();
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Code scanned: ", code.getValue()));
        PrimeFaces.current().ajax().update("form:growl");
    }

If anyone has any idea on how to fix this please let me know thanks in advance.


Solution

  • I don't think your approach with multiple instances is going to work. At least not when you use the same video device on both instances. Different devices might work, but is awkward in my opinion. Since you are now using the same video device on both instances, it is expected that listeners are being called twice.

    What you should do is use a single dialog (so a single scanner) and set a property. This way your dialog and scanner will know for which input it should scan, and you should use that in your listener.