PrimeFaces的 p:commandButton在 p:confirmDialog中将ajax设置为false时不会触发action

前端开发 2026-07-11

我有一个基本需求,使用PrimeFaces的 p:confirmDialog来提问一个简单的是/否问题。最初的想法是使用p:commandButton ajax="true",调用一个动作来更新状态并停留在同一页(使用PF的 @form UI更新+ 向用户显示消息):

<p:confirmDialog global="true"
                 showEffect="fade"
                 hideEffect="fade"
                 responsive="true"
                 style="max-width: 1000px;">
  <p:commandButton value="No"
                   styleClass="ui-button-secondary ui-confirmdialog-no"
                   type="button" />
  <p:commandButton value="Yes"
                   ajax="true"
                   action="#{ergebnisTextbausteinStatusBean.finalizeStatus()}"
                   process="@this"
                   update="@form template_msg_summary"
                   styleClass="ui-confirmdialog-yes" />
</p:confirmDialog>

这按预期工作。动作被调用,数据库中的状态被更新,UI显示一切正常。

现在客户决定改变这个流程,在Yes时导航到另一页(如果成功的话)。

因此,选择尝试一个 <p:commandButton ajax="false">(因为在整个项目中都在使用,所以这个按钮的代码基本上是从项目中其他地方调整而来)。

对话框+ 使用 ajax="false" 的按钮:

<p:confirmDialog global="true"
                 showEffect="fade"
                 hideEffect="fade"
                 responsive="true"
                 style="max-width: 1000px;">
  <p:commandButton value="No"
                   styleClass="ui-button-secondary ui-confirmdialog-no"
                   type="button" />
  <template:formElementSpacer elementWidth="6" elementWidthM="2" />
  <p:commandButton value="Yes"
                   ajax="false"
                   action="#{ergebnisTextbausteinStatusBean.finalizeStatus()}"
                   styleClass="ui-confirmdialog-yes" />
</p:confirmDialog>

然而,动作从未被调用。

随后我安装了一个JSF PhaseListener(在faces-config.xml中挂接)来检查一些事情:

public class AnyPhaseListener implements PhaseListener {

    @Override
    public PhaseId getPhaseId() {
        return PhaseId.ANY_PHASE;
    }

    @Override
    public void beforePhase(PhaseEvent event) {
        System.out.println("----------------- " + getClass().getSimpleName() + " BEFORE PHASE: " + event.getPhaseId());
    }

    @Override
    public void afterPhase(PhaseEvent event) {
        System.out.println("----------------- " + getClass().getSimpleName() + " AFTER PHASE: " + event.getPhaseId());
    }
}

它会打印出每个请求访问的所有阶段。

对于上面这个(工作中的)AJAX true按钮,记录的系统输出如下:

[3/26/26 19:58:26:095 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: RESTORE_VIEW(1)
[3/26/26 19:58:26:105 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: RESTORE_VIEW(1)
[3/26/26 19:58:26:105 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: APPLY_REQUEST_VALUES(2)
[3/26/26 19:58:26:106 CET] 000016f1 HtmlRendererU W   There should always be a submitted value for an input if it is rendered, its form is submitted, and it was not originally rendered disabled or read-only.  You cannot submit a form after disabling an input element via javascript.  Consider setting read-only to true instead or resetting the disabled value back to false prior to form submission. Component : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /pages/auskunftsersuchen/ergebnisTextbaustein.xhtml][Class: javax.faces.component.html.HtmlBody,Id: j_id_d][Class: javax.faces.component.html.HtmlInputHidden,Id: j_id_3h]}
[3/26/26 19:58:26:106 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: APPLY_REQUEST_VALUES(2)
[3/26/26 19:58:26:106 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: PROCESS_VALIDATIONS(3)
[3/26/26 19:58:26:107 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: PROCESS_VALIDATIONS(3)
[3/26/26 19:58:26:107 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: UPDATE_MODEL_VALUES(4)
[3/26/26 19:58:26:108 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: UPDATE_MODEL_VALUES(4)
[3/26/26 19:58:26:108 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: INVOKE_APPLICATION(5)
[3/26/26 19:58:26:108 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: INVOKE_APPLICATION(5)
[3/26/26 19:58:26:109 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: RENDER_RESPONSE(6)
[3/26/26 19:58:26:123 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: RENDER_RESPONSE(6)
[3/26/26 19:58:28:160 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: RESTORE_VIEW(1)
[3/26/26 19:58:28:172 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: RESTORE_VIEW(1)
[3/26/26 19:58:28:173 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: APPLY_REQUEST_VALUES(2)
[3/26/26 19:58:28:173 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: APPLY_REQUEST_VALUES(2)
[3/26/26 19:58:28:173 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: PROCESS_VALIDATIONS(3)
[3/26/26 19:58:28:174 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: PROCESS_VALIDATIONS(3)
[3/26/26 19:58:28:174 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: UPDATE_MODEL_VALUES(4)
[3/26/26 19:58:28:174 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: UPDATE_MODEL_VALUES(4)
[3/26/26 19:58:28:174 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: INVOKE_APPLICATION(5)
[3/26/26 19:58:28:175 CET] 000016f1 SystemOut     O ------------------------- ErgebnisTextbausteinStatusBean.finalizeStatus()!
[3/26/26 19:58:28:175 CET] 000016f1 SystemOut     O ------------------------- 2
[3/26/26 19:58:28:649 CET] 000016f1 SystemOut     O ------------------------- 3
[3/26/26 19:58:30:510 CET] 000016f1 SystemOut     O ------------------------- 4
[3/26/26 19:58:30:510 CET] 000016f1 SystemOut     O ------------------------- 5
[3/26/26 19:58:30:510 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: INVOKE_APPLICATION(5)
[3/26/26 19:58:30:511 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: RENDER_RESPONSE(6)
[3/26/26 19:58:30:661 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: RENDER_RESPONSE(6)
[3/26/26 19:58:34:658 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: RESTORE_VIEW(1)
[3/26/26 19:58:34:667 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: RESTORE_VIEW(1)
[3/26/26 19:58:34:667 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: APPLY_REQUEST_VALUES(2)
[3/26/26 19:58:34:668 CET] 000016f1 HtmlRendererU W   There should always be a submitted value for an input if it is rendered, its form is submitted, and it was not originally rendered disabled or read-only.  You cannot submit a form after disabling an input element via javascript.  Consider setting read-only to true instead or resetting the disabled value back to false prior to form submission. Component : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /pages/auskunftsersuchen/ergebnisTextbaustein.xhtml][Class: javax.faces.component.html.HtmlBody,Id: j_id_d][Class: javax.faces.component.html.HtmlInputHidden,Id: j_id_3h]}
[3/26/26 19:58:34:668 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: APPLY_REQUEST_VALUES(2)
[3/26/26 19:58:34:668 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: PROCESS_VALIDATIONS(3)
[3/26/26 19:58:34:669 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: PROCESS_VALIDATIONS(3)
[3/26/26 19:58:34:669 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: UPDATE_MODEL_VALUES(4)
[3/26/26 19:58:34:669 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: UPDATE_MODEL_VALUES(4)
[3/26/26 19:58:34:670 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: INVOKE_APPLICATION(5)
[3/26/26 19:58:34:670 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: INVOKE_APPLICATION(5)
[3/26/26 19:58:34:670 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: RENDER_RESPONSE(6)
[3/26/26 19:58:34:680 CET] 000016f1 SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: RENDER_RESPONSE(6)

请注意对 finalizeStatus() 的调用,以及我在动作方法中放入的2-3-4-5条系统输出。

AJAX false按钮的输出则不同:

[3/26/26 19:36:38:871 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: RESTORE_VIEW(1)
[3/26/26 19:36:38:879 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: RESTORE_VIEW(1)
[3/26/26 19:36:38:880 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: APPLY_REQUEST_VALUES(2)
[3/26/26 19:36:38:880 CET] 000016eb HtmlRendererU W   There should always be a submitted value for an input if it is rendered, its form is submitted, and it was not originally rendered disabled or read-only.  You cannot submit a form after disabling an input element via javascript.  Consider setting read-only to true instead or resetting the disabled value back to false prior to form submission. Component : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /pages/auskunftsersuchen/ergebnisTextbaustein.xhtml][Class: javax.faces.component.html.HtmlBody,Id: j_id_d][Class: javax.faces.component.html.HtmlInputHidden,Id: j_id_3h]}
[3/26/26 19:36:38:880 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: APPLY_REQUEST_VALUES(2)
[3/26/26 19:36:38:880 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: PROCESS_VALIDATIONS(3)
[3/26/26 19:36:38:881 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: PROCESS_VALIDATIONS(3)
[3/26/26 19:36:38:881 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: UPDATE_MODEL_VALUES(4)
[3/26/26 19:36:38:881 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: UPDATE_MODEL_VALUES(4)
[3/26/26 19:36:38:882 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: INVOKE_APPLICATION(5)
[3/26/26 19:36:38:882 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: INVOKE_APPLICATION(5)
[3/26/26 19:36:38:882 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: RENDER_RESPONSE(6)
[3/26/26 19:36:38:891 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: RENDER_RESPONSE(6)
[3/26/26 19:36:45:492 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: RESTORE_VIEW(1)
[3/26/26 19:36:45:500 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: RESTORE_VIEW(1)
[3/26/26 19:36:45:501 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: APPLY_REQUEST_VALUES(2)
[3/26/26 19:36:45:501 CET] 000016eb HtmlRendererU W   There should always be a submitted value for an input if it is rendered, its form is submitted, and it was not originally rendered disabled or read-only.  You cannot submit a form after disabling an input element via javascript.  Consider setting read-only to true instead or resetting the disabled value back to false prior to form submission. Component : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /pages/auskunftsersuchen/ergebnisTextbaustein.xhtml][Class: javax.faces.component.html.HtmlBody,Id: j_id_d][Class: javax.faces.component.html.HtmlInputHidden,Id: j_id_3h]}
[3/26/26 19:36:45:501 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: APPLY_REQUEST_VALUES(2)
[3/26/26 19:36:45:501 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: PROCESS_VALIDATIONS(3)
[3/26/26 19:36:45:502 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: PROCESS_VALIDATIONS(3)
[3/26/26 19:36:45:502 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: UPDATE_MODEL_VALUES(4)
[3/26/26 19:36:45:503 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: UPDATE_MODEL_VALUES(4)
[3/26/26 19:36:45:503 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: INVOKE_APPLICATION(5)
[3/26/26 19:36:45:503 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: INVOKE_APPLICATION(5)
[3/26/26 19:36:45:504 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener BEFORE PHASE: RENDER_RESPONSE(6)
[3/26/26 19:36:45:515 CET] 000016eb SystemOut     O ----------------- AnyPhaseListener AFTER PHASE: RENDER_RESPONSE(6)

这完全没有系统输出,这个输出让我看到中间缺少一个完整的请求。

不知道另外两个请求,一个在前一个在后,但我们假设它们没问题。

这里的代码/解决方案有什么问题?

我们是在一台较旧的WebSphere 9服务器上,使用JSF 2.2和 PrimeFaces 13.0.10

解决方案

这里有两个注意点。

首先,需要用 ajax=falseaction="#{...}" 声明显示对话框的按钮,并使用一个嵌套的 p:confirm(见下方PF bug的代码示例):

然后(第二点)然而,PrimeFaces 13会触发以下bug:

https://github.com/primefaces/primefaces/issues/12718

为了解决这个问题,根本不要使用 p:confirm

    <p:commandButton value="Do this"
                     type="button"
                     onclick="PF('myDialog').show();" />

p:confirmDialog 上使用一个经典的 widgetVar="",删除 global="true",手动调用 PF('myDialog').show()PF('myDialog').hide(),并让对话框中的按钮调用动作:

    <p:confirmDialog widgetVar="myDialog"
                     header="Security Check"
                     message="Lala"
                     responsive="true" >
        <p:commandButton value="No"
                         type="button"
                         onclick="PF('myDialog').hide();" />
        <p:commandButton value="Yes"
                         ajax="false"
                         action="#{statusBean.doSomething()}" />
    </p:confirmDialog>
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章