Диалоговое окно Primefaces отображается дважды

#jsf #jsf-2 #dialog #primefaces #modal-dialog

#jsf #jsf-2 #диалоговое окно #primefaces #модальный диалог

Вопрос:

Я создал компонент ui: для использования в качестве всплывающего окна, поэтому я могу создавать множество всплывающих окон, используя стандарт этого шаблона. Компонент представляет собой просто всплывающее окно с двумя кнопками (отмена и отправка) и содержимым, которое можно переопределить, как вы можете видеть здесь:

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

Может кто-нибудь сказать мне, почему это происходит??

Комментарии:

1. Можете ли вы также опубликовать код в шаблоне и клиенте шаблонов, который относится к этому фрагменту?

2. Не уверен, что это причина всей проблемы, но проектирование диалогового окна как включаемого файла несколько странно. Файл тегов или составной компонент — более разумный выбор. Кроме того, диалоговое окно также должно иметь свое собственное <h:form> и не должно размещаться внутри любого <h:form> . Вы не хотите отправлять / обрабатывать все другие поля на странице за пределами диалогового окна в той же форме при отправке полей в диалоговом окне.

Ответ №1:

Я опубликовал тот же вопрос на форуме primefaces (как сказал Томми Чан), и кто-то ответил на это:

Вероятно, вы размещаете свой диалог в форме, которую вы обновляете, которая является nono. Никогда не обновляйте диалоговое окно, только содержимое в диалоговом окне

Я пытался сделать это, пока не увидел, что все мои диалоговые окна имеют атрибут «rendered», поступающий с сервера (просто посмотрите Первый 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)">
  

Мне не нравится делать подобные вещи, но я не могу найти лучшего способа решить эту проблему…
Если кто-нибудь даст мне лучшее решение, я буду благодарен

Комментарии:

1. Ha! Это был мой комментарий на форуме primefaces. (Лирионус прав? ;)) причина, по которой я это сказал, заключалась в том, что в ваших обновлениях указано @form … и в вашем диалоговом окне нет тега form вокруг него … так что это означает, что он находится над вашим диалогом… это означает, что ваш диалог находится в форме.

2. Исправлено с помощью этого ответа, в моем случае я обновлял всю форму, а не только компонент. в результате чего диалоговое окно появляется дважды.

Ответ №2:

В моем случае я не могу использовать метод oncompleteI), чтобы скрыть диалоговое окно, потому что оно должно быть закрыто для некоторой бизнес-логики.

В моем случае я использую вкладки primefaces в пользовательском интерфейсе. Каждый раз, когда я перехожу по вкладкам, а затем нажимаю кнопку, на которой появляется диалоговое окно, количество моих диалогов увеличивается пропорционально, поэтому я использовал простой скрипт jquery, чтобы удалить все дублирующие диалоги из пользовательского интерфейса 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();
    }
}
  

Комментарии:

1. Для какого события вы вызываете скрипт?

Ответ №3:

Как я уже говорил на форуме primefaces, вы обновляете свои формы с помощью диалогового окна в нем… вам нужно поместить свои диалоги из вашей формы и обновить их отдельно. Если вам нужно использовать форму в вашем диалоговом окне, поместите ее в свой диалог:

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

Комментарии:

1. Привет, Рафаэль, как я уже говорил, я попробовал этот подход, но приложение очень большое, и этот подход нельзя использовать с этой композицией в общем виде. Это связано с отношением некоторых диалоговых окон. Для этого мне нужно изменить всю логику приложения… Но, конечно, в следующий раз я все сделаю правильно 🙂 Спасибо.

2. @brevleq Ах, я этого не видел, вы пробовали вместо размещения средств визуализации в своем диалоговом окне поместить его в panelgrid. Я знаю, что это дерьмовое решение, но на данный момент я не могу придумать ничего лучшего: p

Ответ №4:

У меня была такая же проблема с диалогом, решение было размещено в обновлении командной кнопки, которая показывает компоненту диалога конкретный идентификатор компонента диалога, а не идентификатор формы, решение выглядит следующим образом:

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

Ответ №5:

Я бы проверил, чтобы ваш widgetVar=»#{idPopup}» id =»#{idPopup}» был одинаковым перед отправкой и после отправки формы. Возможно, оно изменилось, и primefaces считает, что оно больше не существует, и создает новое.

Комментарии:

1. идентификатор двух диалоговых окон один и тот же: cadastroEmpresa:popupNovoCadastroEmpresa

2. возможно, задайте вопрос на форуме primefaces … пользователи там очень отзывчивы.

3. widgetVar PrimeFaces и идентификатор JSF не должны совпадать. Я прочитал это «золотое» правило в сообщении самого Оптимуса где-то на форумах. Не могу найти его прямо сейчас.

Ответ №6:

Добавьте oncomplete атрибут к вашей кнопке отправки и позвольте ему скрыть диалоговое окно:

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

Комментарии:

1. Я уже пробовал эту опцию, диалоговое окно открывается дважды, но они немедленно закрываются.

Ответ №7:

размещение форм внутри диалогового окна — не лучший способ решить эту проблему, если вы получаете доступ к своему приложению с помощью iExplorer, диалоги не будут работать при таком подходе

Комментарии:

1. Что-то подобное происходит со мной, я использую ajax для отправки содержимого форм, и каждый раз, когда я нажимаю на кнопку, которая показывает мне диалоговое окно, оно отображает столько диалогов, сколько отправлено через ajax, я видел, что если я обновлю всю страницу, она начнется снова (отображение 1 диалога, 2, 3 и т.д.)

Ответ №8:

Это ужасная ошибка без официального ответа…

Я использую диалоговое окно для отображения карты Google. Способ, которым я справляюсь с ошибкой (с помощью jQuery), заключается в подсчете количества элементов «.map» в DOM в primefaces: dialog.На шоу… Затем я выбираю:последний отображаемый экземпляр .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. Кнопка закрытия должна полностью уничтожить диалоговое окно.