【问题标题】:Primefaces dialog is rendering twicePrimefaces 对话框正在渲染两次
【发布时间】:2011-12-14 09:32:37
【问题描述】:

我创建了一个 ui:component 来像弹出窗口一样使用,所以我可以使用这个模板的标准创建很多弹出窗口。 该组件只是一个带有两个按钮(取消和提交)和一个可以被覆盖的内容的弹出窗口,就像您在此处看到的那样:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.prime.com.tr/ui">
<ui:component>
<p:dialog widgetVar="#{idPopup}" id="#{idPopup}" modal="#{popup.modal}"
    draggable="#{popup.modal}"
    rendered="#{popup.visivel}" visible="#{popup.visivel}"
    closeOnEscape="false" closable="false" header="#{titulo}"
    resizable="false" styleClass="autoWidthDialog" showEffect="fade"
    hideEffect="fade">
    <h:panelGroup style="width:100%">
        <p:focus />
        <ui:insert name="conteudo">Nenhum conteúdo definido!</ui:insert>
        <h:panelGrid id="#{idPopup}PainelMensagens" style="width:100%">
            <p:messages />
        </h:panelGrid>
        <ui:insert name="barraDeBotoes">
            <h:panelGroup layout="block" style="width:100%">
                <p:commandButton value="CANCELAR" immediate="true" update="@form"
                    style="float:right" action="#{controladorPopup.fechar}"
                    onclick="#{idPopup}.hide();" />
                <p:commandButton value="OK" style="float:right"
                    update="@form formAlerta"
                    action="#{controladorPopup.submit}"
                    process="@form" />
            </h:panelGroup>
        </ui:insert>
    </h:panelGroup>
</p:dialog>
</ui:component>
</html>

当我尝试在未填写必填字段的情况下提交表单时会出现问题。正确的行为是再次显示带有消息的弹出窗口,但对话框呈现两次,一次带有消息,另一次不带消息。 您可以在此处查看此行为:

这是此模板的一种用途:

<ui:composition template="../templates/popupSubmit.xhtml">
<ui:param name="titulo" value="Buscar pessoa" />
<ui:param name="popup" value="#{modeloPopupBuscaPessoa}" />
<ui:param name="controladorPopup"
    value="#{controladorPopupBuscaPessoa}" />
<ui:define name="conteudo">
    <h:panelGroup>
        <h:panelGrid columns="2">
            <h:outputLabel value="Tipo de cadastro:" style="float:none" />
            <h:selectOneMenu value="#{controladorSugestaoPessoa.tipoCadastro}"
                immediate="true">
                <f:selectItems value="#{carregadorTipoCadastro.itens}" />
                <f:ajax event="change" immediate="true" />
            </h:selectOneMenu>
        </h:panelGrid>
        <h:outputText value="Buscar por:" />
        <h:selectOneRadio value="#{controladorSugestaoPessoa.tipoBusca}"
            immediate="true">
            <f:selectItems value="#{carregadorTipoBuscaPessoa.itens}" />
            <f:ajax event="change" immediate="true" />
        </h:selectOneRadio>
        <p:autoComplete value="#{modeloPopupBuscaPessoa.itemSelecionado}"
            forceSelection="true" maxResults="10" queryDelay="500" 
            completeMethod="#{controladorSugestaoPessoa.atualizarSugestoes}"
            var="pessoa" itemLabel="#{pessoa.label}" itemValue="#{pessoa}"
            converter="#{conversorSelectItem}" />
    </h:panelGroup>
</ui:define>
</ui:composition>

还有这些用处:

<h:form id="cadastroPessoa">
    <ui:include
        src="resources/components/popups/modulo_cadastro/popupNovoCadastroPessoa.xhtml">
        <ui:param name="idPopup" value="popupNovoCadastroPessoa" />
    </ui:include>
    <ui:include
        src="resources/components/popups/modulo_cadastro/popupCadastroPessoa.xhtml">
        <ui:param name="idPopup" value="popupEdicaoCadastroPessoa" />
    </ui:include>
    <ui:include
        src="resources/components/popups/modulo_cadastro/popupBuscaPessoa.xhtml">
        <ui:param name="idPopup" value="popupBuscaCadastroPessoa" />
    </ui:include>
</h:form>

<h:form id="cadastroProduto">
    <ui:include
        src="resources/components/popups/modulo_cadastro/popupCadastroProduto.xhtml">
        <ui:param name="idPopup" value="popupNovoCadastroProduto" />
    </ui:include>
</h:form>

谁能告诉我为什么会这样??

【问题讨论】:

  • 能否把与该片段相关的模板和模板客户端中的代码也贴出来?
  • 不确定是否是整个问题的原因,但将对话框设计为包含文件有点奇怪。标记文件或复合组件是更明智的选择。此外,对话框还应该有自己的&lt;h:form&gt;,而不是放在任何&lt;h:form&gt; 中。提交对话框中的字段时,您不希望以相同的形式提交/处理对话框外页面中的所有其他字段。

标签: jsf jsf-2 dialog primefaces modal-dialog


【解决方案1】:

这是一个没有官方答案的可怕错误......

我正在使用对话框来呈现 Google 地图。我处理错误的方式(使用 JQuery)是通过在 primefaces:dialog.onShow 上计算 DOM 中“.map”元素的数量...然后我选择呈现的 :last .map 实例(或者在你的情况下,无论如何您正在使用的内容类),以及 .remove() 包含它的对话框:

标记(大约):

<pri:dialog onShow="popupOpen();" etc...>
    <div id="map" class"map"></div>
</pri:dialog>

JavaScript:

function onShowDialog(){
    if($(".map").length > 1){
        $cull = $(".map:last");
        $cull.closest(".ui-dialog").remove();
    }
}

如果你是一个虐待狂,你可以很轻松地把它做成一个单线……我认为这是一个 Primefaces 错误。关闭按钮应该彻底破坏对话框。

【讨论】:

    【解决方案2】:

    我在对话框中遇到了同样的问题,解决方案是在 commandButton 的更新中显示对话框组件的特定 id 而不是表单 id,解决方案如下所示:

        <p:dialog id="dialogId">
            <p:commandButton value="OK" style="float:right"
                 update="@form dialogId"
                 action="#{controladorPopup.submit}"
                 process="@form"/>
        </p:dialog>
    

    【讨论】:

      【解决方案3】:

      在我的情况下,我不能使用 oncompleteI) 方法来隐藏对话框,因为它必须对某些业务逻辑关闭。

      在我的情况下,我在 UI 上使用了 primefaces 选项卡。每次我浏览选项卡然后单击出现对话框的按钮时,我的对话框数量都会增加比例 所以我使用简单的 jquery 脚本从 UI 中删除所有重复对话框 用户界面。

      function removeDuplicateDialogs(dialogId) {
      
          \\ generally all our components have : character we have to 
          \\ replace ':' with '\\:'(applying escape character)
          dialogId = dialogId.replace(/\:/g, '\\:');
      
          var dialogs = jQuery("div[id=" + dialogId + "]");
          var numOfDialogs = dialogs.length;
          numOfDialogs = numOfDialogs - 1;
          for (var i = 0; i < numOfDialogs; i++) {
              jQuery(dialogs[i]).remove();
          }
      }
      

      【讨论】:

      • 您在哪个事件上调用脚本?
      【解决方案4】:

      将表单放入对话框并不是解决问题的最佳方法,如果您使用 IExplorer 访问您的应用程序,对话框将无法使用这种方法

      【讨论】:

      • 类似的事情发生在我身上,我使用 ajax 发送表单内容,每次我点击显示对话框的按钮时,它都会呈现与我通过 ajax 提交的一样多的对话框,我已经看到,如果我刷新整个页面,它将重新开始(渲染 1 个对话框、2、3 等)
      【解决方案5】:

      正如我在 primefaces 论坛上所说,您正在使用其中的对话框更新您的表单...您需要将您的对话框从您的表单中取出并单独更新它们。如果您需要在对话框中使用表单,请将其放在对话框中:

         <p:dialog><p:form> </p:form> </p:dialog>
      

      【讨论】:

      • 嗨 Rafael,正如我所说,我尝试了这种方法,但应用程序非常大,这种方法不能以通用方式与该组合一起使用。这是因为某些对话框的关系。为此,我需要更改所有应用程序逻辑......但我下次肯定会以正确的方式实现 :) 谢谢。
      • @brevleq 啊,没看到,您是否尝试过将渲染器放置在对话框中,而不是将其放置在面板网格中。我知道这是一个糟糕的解决方案,但目前我想不出更好的解决方案:p
      【解决方案6】:

      我在 primefaces 论坛上发布了同样的问题(就像 Tommy Chan 所说的那样),有人回答了这个问题:

      您可能正在将您的对话框放置在您正在更新的表单中,这是一个 nono。永远不要只更新对话框中的内容

      我一直尝试这样做,直到我看到我的所有对话框都具有来自服务器的“渲染”属性(只需查看第一个 xml),我在此应用程序中有很多对话框,其中一些与其他对话框有关系(在服务器上),最后这些在同一个表单上。

      我做了一些不同的事情,我只创建了这个 javascript 代码:

      function removerDialogo(id) {
         setTimeout(function() {
             removerDialogoAposIntervalo(id);
         }, 100);  
      }
      
      function removerDialogoAposIntervalo(id) { 
         id = id.replace(':', '\\:');
         jQuery('div.ui-dialog')
             .find('#' + id)
             .parent().eq(1)
             .remove(); 
      }
      

      并在对话框“onShow”属性中调用它:

      <p:dialog widgetVar="#{idPopup}" id="#{idPopup}" modal="#{popup.modal}"
          draggable="#{popup.modal}" rendered="#{popup.visivel}"
          visible="#{popup.visivel}" closeOnEscape="false" closable="false"
          header="#{titulo}" resizable="false" styleClass="autoWidthDialog"
          showEffect="fade" hideEffect="fade" onShow="removerDialogo(this.id)">
      

      我不喜欢做这样的事情,但我找不到更好的方法来解决这个问题...... 如果有人给我更好的解决方案,我将不胜感激

      【讨论】:

      • 哈!这是我在 primefaces 论坛上的评论。 (Lyrionus 对吗?;))我之所以这么说是因为您的更新说@form ...并且您的对话框周围没有表单标签...所以这意味着它在您的对话框上方...这意味着您的对话框在表格中。
      • 修复了这个答案,在我的情况下,我正在更新所有表单而不仅仅是组件。导致对话框出现两次。
      【解决方案7】:

      将oncomplete 属性添加到您的提交按钮并让它隐藏对话框:

      <p:commandButton value="OK" style="float:right"
                       update="@form formAlerta"
                       action="#{controladorPopup.submit}"
                       process="@form"
                       oncomplete="#{idPopup}.hide();"/>
      

      【讨论】:

      • 我已经尝试过这个选项,对话框打开了两次,但它们立即关闭。
      【解决方案8】:

      我会检查您的 widgetVar="#{idPopup}" id="#{idPopup}" 在您提交之前和提交表单之后是否相同。也许它已经改变了,primefaces 认为它​​不再存在并创建了一个新的。

      【讨论】:

      • 两个对话框的id相同:cadastroEmpresa:popupNovoCadastroEmpresa
      • 也许可以在 primefaces 论坛上提问...那里的用户反应非常好。
      • PrimeFaces widgetVar 和 JSF id 不得相同。我在论坛某个地方的 Optimus 自己的帖子中读到了这条“黄金”规则。目前找不到。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多