首页 > 解决方案 > 为什么 JSF 表单即使有值也要保持验证样式?

问题描述

我有一个表单(frmAddPax)来添加一些用户数据。该数据可以手动提交或通过条形码阅读器提交。当按下“Escanear”按钮时,此按钮将调用另一个表单 (frmScan) 的对话框。

此表单从条形码阅读器读取一些数据,并在托管 bean 中处理这些数据。数据创建一个以原始形式 (frmAddPax) 使用的对象。

问题是所有表单都有样式,因为上面没有任何数据,所有必填字段都有 required="true" 属性。

在此处输入图像描述

如果我再次按下“Escanear”按钮并扫描相同的数据,它会显示表格就好了。

在此处输入图像描述

我认为这可能是因为在表单中的数据准备好更新之前,验证过程已经发生,但是正如我在一些问题中看到的那样,动作actionListener事件发生在更新过程之前,所以我不知道。

这是表单的代码:

<h:form id="frmAddPax"
rendered="#{MB.renderStatus.isRenderFormAddPax()}">
<p:panelGrid styleClass="no-border">
    <p:row>
        <p:column>
            <h:outputText
                value="#{label['manageVipLoungeEntrance.addPassenger.firstName']} />
        </p:column>
        <p:column>
            <p:inputText required="true"
                value="#{manageVipLoungeEntranceExtMB.passenger.firstName}"
                style="text-transform: uppercase;" converter="upperCaseConverter">
                <f:ajax event="blur" update="@this" render="@this" />
            </p:inputText>
        </p:column>
        ...
        ...
        <!-- BOTON ESCANEAR AGREGAR PASAJERO -->
        <p:column>
            <p:commandButton inmediate="true"
                value="#{label['manageVipLoungeEntrance.addPassenger.button.scan']}"
                onclick="showLocalDate()" update=":frmScan"
                actionListener="#{manageVipLoungeEntranceExtMB.clear}"
                oncomplete="{wgvScan.show()}" />
        </p:column>
        <!-- BOTON ESCANEAR AGREGAR PASAJERO -->
    </p:row>
</p:panelGrid>

这是产生“Escanear”按钮的调用代码:

<p:commandButton inmediate="true"
    value="#{label['manageVipLoungeEntrance.addPassenger.button.scan']}"
    onclick="showLocalDate()" update=":frmScan"
    actionListener="#{manageVipLoungeEntranceExtMB.clear}"
    oncomplete="{wgvScan.show()}" />

这是处理条形码读取并使用处理过的数据更新原始表单的小部件的代码。

<p:dialog widgetVar="wgvScan" modal="true" showEffect="fade"
            closeOnEscape="true" resizable="false">
  <h:form id="frmScan">
        <p:graphicImage value="../resources/images/barCode.png"
            rendered="#{manageVipLoungeEntranceExtMB.showTablePassenger!=true}" />
        <p:inputText id="itbarcode"
            rendered="#{manageVipLoungeEntranceExtMB.showTablePassenger!=true}"
            value="#{manageVipLoungeEntranceExtMB.barCode}" onfocus="true"
            autocomplete="off" styleClass="insertData"
            style="background:#ffffff; position:absolute;left:-7000;" />
        <p:commandButton id="cmdReadBarcode" style="display:none"
            onclick="showLocalDate()"
            actionListener="#{manageVipLoungeEntranceExtMB.readBarCode}"
            update=":frmAddPax :growl">
        </p:commandButton>
        <p:defaultCommand target="cmdReadBarcode" />
        ...
    </h:form>

[编辑] @alibttb 回答让我找到解决方案。

我在调用对话框以侦听扫描仪的按钮之前添加了一个 remoteCommand。

<p:remoteCommand name="refreshForm" process=":frmAddPax" update=":frmAddPax" />
    <p:commandButton
        value="#{label['manageVipLoungeEntrance.addPassenger.button.scan']}"
        onclick="showLocalDate()" process="@this" update=":frmScan"
        actionListener="#{manageVipLoungeEntranceExtMB.clear}"
        oncomplete="{wgvScan.show()}" />
</p:column>

在处理条形码的表单对话框中,我添加了一个调用 remoteCommand 的onHide属性。我按照建议将对话框表单的附件更改为表单对话框。

<h:form id="frmScan">
<p:dialog widgetVar="wgvScan" modal="true" showEffect="fade"
    closeOnEscape="true" resizable="false" onHide="refreshForm()">

标签: primefacesjsf-2

解决方案


当您单击Escanear按钮时发生的情况是您正在处理整个表单,因此提交所有具有空值的字段,这将导致验证错误,您的按钮是即时的,所以会发生以下情况:

  1. actionListener 是即时的,因此首先调用它,托管 bean 填充来自条形码扫描仪的数据。
  2. 表单数据正在被验证并且它无效,因此在所有输入上都设置了 inValid 标志。
  3. 在包含表单更新的服务器上创建响应,显示来自托管 bean 的新值以及来自验证过程的输入的 inValid 状态。

请注意,提交的数据(空值)未应用于模型,因为它无效。

要解决这个问题,只需在您的按钮上使用部分处理功能,并删除 immediate="true",这只是一个糟糕的设计。

只需将Escanear按钮中的 immediate="true" 替换为 process="@this"即可。

如果您不熟悉 JSF 和 primefaces 的部分处理功能,您应该看看。

如果您确实需要在扫描完成后提交表单进行验证,那么您需要使用p:remoteCommand在 actionListener 完成后提交表单:

    <p:remoteCommand name="validateForm" process="@form"/>

    <p:commandButton value="#{label['manageVipLoungeEntrance.addPassenger.button.scan']}"
    onclick="showLocalDate()" update=":frmScan" process="@this"
    actionListener="#{manageVipLoungeEntranceExtMB.clear}" 
    oncomplete="{wgvScan.show()}" />

并以另一种形式frmScan

<h:form id="frmScan">
<p:dialog widgetVar="wgvScan" modal="true" showEffect="fade"
        closeOnEscape="true" resizable="false" onHide="validateForm()">
....
....complete your code

的名称p:remoteCommand成为一个 javascript 函数,一旦扫描对话框被隐藏,就可以回调该函数。

注意在浏览器中打开开发控制台并观察两个请求,一个是更新表单并关闭对话框,另一个是p:remoteCommand验证表单。

注意 1(与您的问题无关)我用frmScan来附上p:dialog这是正确的方法,表单应该围绕对话框而不是相反。


推荐阅读