Primefaces 对话框渲染两次

发布于 2024-12-11 19:14:19 字数 4585 浏览 1 评论 0原文

我创建了一个 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>

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

twiceRender

这是此模板的一种用途:

<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>

有人可以告诉吗我为什么会这样?

I've created an ui:component to use like a popup, so I can create a lot of popups using the standard of this template.
The component is just a popup with two buttons (cancel and submit) and a content that can be overriden, like you can see here:

<!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>

The problem happen when I try to submit the form without filling the required fields. The correct behavior is just show again the popup with messages, but the dialog is rendered twice, one with the messages and one without the messages.
You can see this behavior here:

twice rendering

this is one use of this template:

<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>

And these are some use:

<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>

Could someone tell me why this is happening??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

落墨 2024-12-18 19:14:19

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

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

我尝试这样做,直到我看到所有对话框都有来自服务器的“渲染”属性(只需查看第一个 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)">

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

I've posted the same question in primefaces forum (like Tommy Chan told), and someone answered this:

You are probably placing your dialog in the form you are updating which is a nono. Never update the dialog only the stuff in the dialog

I've tried to do this until I saw all my dialogs have "rendered" attribute coming from server (just see the first xml), I have a lot of dialogs in this application and some of them have relation with others (on server), these last are on the same form.

I did something different, I only created this javascript code:

function removerDialogo(id) {
   setTimeout(function() {
       removerDialogoAposIntervalo(id);
   }, 100);  
}

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

and called this on dialog "onShow" attribute:

<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)">

I don't like to do things like this, but I can't find a better way to solve this...
If someone give me a better solution, I will be grateful

囍孤女 2024-12-18 19:14:19

就我而言,我无法使用 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();
    }
}

In my case I cannot user oncompleteI) method to hide the dialog because it has to be closed to some business logic.

I my case I have use primefaces tabs on UI. Every time I navigate the tabs and then click on button on which dialog appears then my dialogs number are increasing proportionality
So I have used simple jquery script to remove all the duplication dialog from the UI
e 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();
    }
}
挖鼻大婶 2024-12-18 19:14:19

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

如果您需要在对话框中使用表单,请将其放入对话框中:

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

As I said on the Primefaces forum, you are updating your forms with the dialog in it... you need to place your dialogs out of your form and update them separately.

If you need to use a form in your dialog then place it in your dialog:

<p:dialog>
  <p:form> 
  </p:form>
</p:dialog>
℉服软 2024-12-18 19:14:19

我在对话框中遇到了同样的问题,解决方案被放置在命令按钮的更新中,该命令按钮向对话框组件显示对话框组件的特定 id,而不是表单 id。

解决方案如下所示:

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

I had the same problem with a dialog, and the solution was placed in the update of the commandButton that shows the dialog component the specific id of the Dialog Component, not the form id.

The solution looks like this:

<p:dialog id="dialogId">
    <p:commandButton value="OK" style="float:right"
         update="@form dialogId"
         action="#{controladorPopup.submit}"
         process="@form"/>
</p:dialog>
墨小墨 2024-12-18 19:14:19

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

I would check that your widgetVar="#{idPopup}" id="#{idPopup}" is the same before you submit and after you submit the form. Maybe it has changed and primefaces thinks it doesn't exist anymore and creates a new one.

香橙ぽ 2024-12-18 19:14:19

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

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

Add the oncomplete attribute to your submit button and let it hide the dialog:

<p:commandButton value="OK" style="float:right"
                 update="@form formAlerta"
                 action="#{controladorPopup.submit}"
                 process="@form"
                 oncomplete="#{idPopup}.hide();"/>
彼岸花似海 2024-12-18 19:14:19

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

putting the forms inside dialog isnt the best way to solve it, if you access your application with IExplorer, dialogs wont work with this approach

偏爱你一生 2024-12-18 19:14:19

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

我正在使用一个对话框来渲染谷歌地图。我处理 bug 的方法(使用 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 漏洞。关闭按钮应该彻底破坏对话框。

This is an awful bug with no official answer...

I'm using a dialog to render a Google map. The way I handle the bug (using JQuery) is by counting the number of ".map" elements in the DOM on primefaces:dialog.onShow... I then select the :last .map instance rendered (or in your case, whatever content class you're working with), and .remove() the dialog which contains it:

Markup (approx):

<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();
    }
}

If you're a sadist you could, quite comfortably, make that a one liner... I see this as a Primefaces bug. The close button should outright destroy the dialog.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文