Очистить форму в диалоговом окне p: при закрытии после неудачного вызова действия/метода

У меня есть форма в компоненте p:dialog, которая отправляется через AJAX. Форма в диалоге находится через ui:include другого .xhtml, содержащего только форму и ее компоненты (нет, я не вкладываю формы; сам диалог не находится ни в какой форме). Поддерживающий компонент включенной страницы — ViewScoped.

БОЛЬШИНСТВО вещей работает нормально:

  • При успешной проверке форма выполнит метод сохранения; после успешного сохранения диалог закрывается; открытие последующей записи показывает правильную информацию о записи из базы данных.
  • При неудачной проверке отправленные значения сохраняются, а диалоговое окно остается открытым и отображает ошибки проверки, исправляя недопустимые поля и повторно отправляя результаты при успешном сохранении.

Проблема возникает, когда action, вызванный p:commandButton, дает сбой. В случае неудачи диалоговое окно остается открытым и отображает пользователю "Ошибка сохранения изменений" через h:messages; кроме того, отправленные значения по-прежнему сохраняются в полях ввода. Это нормально (и даже желательно), пока форма остается открытой, однако при закрытии диалогового окна и повторном его открытии отправленные значения ОСТАЮТСЯ в текстовых полях. Это плохо, потому что у пользователя создается впечатление, что сохранение прошло успешно (поскольку компонент h:messages теперь пуст из-за обновления диалога).

До сих пор я пробовал следующее, НИ ОДИН из которых не устранил проблему:

  • 1.1) Установка вспомогательного компонента включенной формы в новый экземпляр компонента при открытии диалогового окна.
  • 1.2) Поскольку компонент теперь является новым экземпляром, я также повторно заполняю адресный объект деталями из компонента данных.
  • 2.1) Отключение кнопки закрытия в диалоге и добавление кнопки p:commandButton "Отмена" с компонентом p:resetInput для закрытия диалога/сброса формы. (диалог закрывается, но отправленные значения в форме сохраняются).
  • 2.2) Вызов метода из этого p:commandButton, который удаляет RequestMap для вспомогательного компонента включенной формы.
  • 2.3) Пробовал с кнопкой, установленной как на immediate=true, так и на immediate=false.
  • 2.4) Пробовал с кнопкой, установленной на process=@this, аналогичную тактику, которую я использовал, чтобы закрыть форму, чтобы убедиться, что при повторном открытии в ней будут новые поля.

Вы могли бы подумать, что между установкой вспомогательного компонента в новый экземпляр и повторным заполнением объекта адреса я увижу новую форму, но НЕТ.

Вот часть исходников:

Часть mainform.xhtml

    <p:dialog id="dlgAddress"
              header="Address Edit"
              widgetVar="dialogAddress"
              dynamic="true"
              modal="false"
              closable="false"
              resizable="false"
              styleClass="dlgAddress"
              visible="#{addressform.showDlgAddress}">
        <ui:include src="addressform.xhtml"/>
    </p:dialog>

addressform.xhtml

<h:form id="fDlgAddress">
    <div id="addresses-container">
        <h:messages id="msgDlgAddress" errorClass="errormsg" infoClass="infomsg1" layout="table"/>
        <h:panelGrid columns="1"
                     styleClass="pgAddresses"
                     rendered="#{!addressform.address.exists}">
            <h:outputText value="No active #{addressform.address.atypCode} address found."
                          styleClass="record-not-exists"/>
            <h:outputText value="Use the form below to create one."/>
        </h:panelGrid>
        <p:panelGrid columns="2"
                     styleClass="pgDlgForm pgAddresses">
            <h:outputLabel value="Address Type"/>
            <h:inputText id="atypCode1"
                         value="#{addressform.address.atypCode}"
                         disabled="true"
                         rendered="#{addressform.address.exists}"/>
            <h:selectOneMenu id="atypCode2"
                             value="#{addressform.address.atypCode}"
                             rendered="#{!addressform.address.exists}">
                <f:selectItems value="#{addressform.atypCodeList}"
                               var="atyp"
                               itemValue="#{atyp}"
                               itemLabel="#{atyp}"/>
            </h:selectOneMenu>
            <h:outputLabel value="Street 1" 
                           for="street1"/>
            <h:inputText id="street1"
                         value="#{addressform.address.addressLine1}"/>
            <h:outputLabel value="Street 2" 
                           for="street2"/>
            <h:inputText id="street2"
                         value="#{addressform.address.addressLine2}"/>
            <h:outputLabel value="Street 3" 
                           for="street3"/>
            <h:inputText id="street3"
                         value="#{addressform.address.addressLine3}"/>
            <h:outputLabel value="Street 4" 
                           for="street4"/>
            <h:inputText id="street4"
                         value="#{addressform.address.addressLine4}"/>
            <h:outputLabel value="City" 
                           for="city"/>
            <h:inputText id="city"
                         value="#{addressform.address.city}"
                         required="true"
                         requiredMessage="Please enter a city."/>
            <h:outputLabel value="State" 
                           for="statCode"/>
            <h:selectOneMenu id="statCode"
                             value="#{addressform.address.stateCode}">
                <f:selectItem itemLabel="Select State/Province"
                              itemValue=""/>
                <f:selectItems value="#{states.statesList}"
                               var="stat"
                               itemValue="#{stat.statCode}"
                               itemLabel="#{stat.statDesc}"/>
            </h:selectOneMenu>
            <h:outputLabel value="Zip Code" 
                           for="zipCode"/>
            <h:inputText id="zipCode"
                         value="#{addressform.address.zip}"/>
            <h:outputLabel value="Country" 
                           for="natnCode"/>
            <h:selectOneMenu id="natnCode"
                             value="#{addressform.address.nationCode}"
                             required="true"
                             requiredMessage="Please choose a nation.">
                <f:selectItem itemLabel="Select Country"
                              itemValue=""/>
                <f:selectItems value="#{nations.nationsList}"
                               var="natn"
                               itemValue="#{natn.natnCode}"
                               itemLabel="#{natn.natnDesc}"/>
            </h:selectOneMenu>
            <h:outputLabel value="From Date" 
                           for="fromDate"/>
            <p:calendar id="fromDate"
                        value="#{addressform.address.fromDate}"
                        showButtonPanel="true"/>
            <h:outputLabel value="To Date" 
                           for="toDate"/>
            <p:calendar id="toDate"
                        value="#{addressform.address.toDate}"
                        showButtonPanel="true"/>
            <h:outputLabel value="Inactivate"
                           for="inactivateAddress"
                           rendered="#{addressform.address.exists}"/>
            <h:selectBooleanCheckbox id="inactivateAddress"
                                     value="#{addressform.address.inactivate}"
                                     rendered="#{addressform.address.exists}"/>
            <h:outputLabel value="Delete"
                           for="deleteAddress"
                           rendered="#{addressform.address.exists}"/>
            <h:selectBooleanCheckbox id="deleteAddress"
                                     value="#{addressform.address.delete}"
                                     rendered="#{addressform.address.exists}"/>
        </p:panelGrid>
    </div>
    <div class="button-container">
        <p:commandButton value="Save Changes"
                         action="#{addressform.save}"
                         type="submit"
                         ajax="true"
                         process="@form"
                         update="@form"/>
        <p:commandButton value="Cancel"
                         process="@this"
                         onclick="dialogAddress.hide();">
            <p:resetInput target="fDlgAddress"/>
        </p:commandButton>
    </div>
</h:form>

Recorddetailsform (компонент поддержки для формы, из которой вызывается диалоговое окно адреса)

public void showDlgAddress(){
        FacesContext ctx = FacesContext.getCurrentInstance();
        ELResolver resolver = ctx.getApplication().getELResolver();
        RecordDetails recordDetails = (RecordDetails) resolver.getValue(ctx.getELContext(), null, "recordDetails");

        //Set addressform backing bean to new instance and load address into it from recordDetails
        resolver.setValue(ctx.getELContext(), null, "addressform", new Addressform());
        Addressform addressform = (Addressform) resolver.getValue(ctx.getELContext(), null, "addressform");
        addressform.setAddress(recordDetails.getAddress());
    }

Addressform (компонент адресной формы)

public void save() {
    FacesContext ctx = FacesContext.getCurrentInstance();
    RequestContext rctx = RequestContext.getCurrentInstance();
    ELResolver resolver = ctx.getApplication().getELResolver();
    Records records = (Records) resolver.getValue(ctx.getELContext(), null, "records");
    RecordDetails recordDetails = (RecordDetails) resolver.getValue(ctx.getELContext(), null, "recordDetails");
    Mainform mainform = (Mainform) resolver.getValue(ctx.getELContext(), null, "mainform");
    Person person = (Person) resolver.getValue(ctx.getELContext(), null, "person");

    //Pretty lengthy SQL stuff here. Commented out. Just wanted to display the display logic below for the dialog.

    if (errorMsg != null) {//If errorMsg is not null, then error occurred.
        showDlgAddress = true;//Ensures address dialog remains open in event of action error.
        queueErrorMessage(errorMsg);
        rctx.update("dlgAddress");
        return;//break out of method on error.
    } else {
        showDlgAddress = false;
        rctx.update("dlgAddress");
    }

    //If everything saves without error, repopulate address and update recordDetails dialog.
    recordDetails.populateAddress(records.getSelectedRecord());
    mainform.updateDlgRecordDetails();
}

Другая информация:

  • JSF2
  • Перволики 3.5
  • Томкэт 6.0
  • NetBeans

person mousouchop    schedule 26.04.2013    source источник


Ответы (2)


Попробуй это:

  1. Поместите свой диалог в форму (dialogInputForm)

  2. Добавьте атрибут update=":dialogInputForm"

  3. Вложите тег resetInput в кнопку, которая открывает диалоговое окно, и укажите цель как только что созданную форму.

Кнопка команды:

<p:commandButton process="@this" actionListener="#{bean.prepare}" update=":dialogInputForm" oncomplete="thirdPartyDialog.show()" value="Open Input Dialog" >
     <p:resetInput target=":dialogInputForm" />
</p:commandButton>

И форма, которая содержит диалог

<h:form id="dialogInputForm" >
 ... your dialog ...
</h:form>
person Rafael Companhoni    schedule 26.04.2013
comment
Хммм... Я могу попробовать это на работе завтра, но, кажется, я уже пробовал это. В результате p:resetInput заставил форму выглядеть так, как будто никакая запись не была загружена, очищая не только застрявшие отправленные значения из предыдущей записи для очистки, но также и значения новой входящей записи. - person mousouchop; 28.04.2013
comment
Невероятно это решение работает! Я был в отчаянии из-за этой проблемы сброса значений моих диалогов. <p:resetInput target=":dialogInputForm"/> делает свое дело. Большое спасибо! - person Grégoire C; 12.03.2014
comment
да. Я обнаружил, что это работает надежно. Однако я вставляю свои формы в свой диалог, что, похоже, не вызывает проблем. Я думаю, что моя проблема возникла, когда я сначала попытался использовать @form в качестве цели для <p:resetInput/>. Вы ДОЛЖНЫ использовать фактический идентификатор формы в этом компоненте, а также обновить ту же форму, что и в приведенном выше примере. Спасибо. - person mousouchop; 23.05.2014
comment
Пробовал, работает, только если цель на самом деле является формой, не работает, если это идентификатор клиента составного компонента (документы говорят, что любой родительский компонент будет работать). Грустный. Мне придется объединить идентификаторы, и в какой-то момент код станет хрупким. Но пока сойдет. - person jpangamarca; 14.02.2017
comment
Я попробовал ваше решение и никогда не работал над компонентом, управляемым сеансом. - person Nemuga Dev; 04.06.2021

Это сработало для меня, поместите это событие ajax в диалоговое окно. Когда диалог закрыт, проверки будут очищены

<p:dialog id="dlgAddress"
              header="Address Edit"
              widgetVar="dialogAddress"
              dynamic="true"
              modal="false"
              closable="false"
              resizable="false"
              styleClass="dlgAddress"
              visible="#{addressform.showDlgAddress}">
        <ui:include src="addressform.xhtml"/>

   <p:ajax event="close" update="dlgAddress" resetValues="true" />

</p:dialog>
person borchvm    schedule 20.06.2019
comment
Я попробовал ваше решение и никогда не работал над компонентом, управляемым сеансом. - person Nemuga Dev; 04.06.2021