Дублирующиеся сообщения в диалоговом окне и на странице

Я работаю с Primefaces 5.2, JSF 2.2.10 и Tomcat 7.0.

У меня есть страница пользователя с его личными данными и одна кнопка, которая позволяет этому пользователю изменить свой пароль через диалог.

На странице я использую компонент p:messages (с id="messages") и другой компонент p:messages (с id="messagesDialog") внутри диалогового окна.

Чтобы изменить свой пароль, пользователь должен ввести свой текущий пароль и новый.

Когда поля диалога не проходят проверку, я хотел бы показать ошибки внутри компонента диалоговых сообщений («messagesDialog»), но не в компоненте сообщений страницы («сообщения»).

Как я мог это получить?

Подробное изображение

Я пытался использовать поле внутри контроллера, которое истинно, когда диалоговое окно открыто, и ложно, когда оно закрыто. Сообщения страницы («сообщения») имеют атрибут rendered с этим полем. Но это не сработало.

Это код, который я использую:

XHTML-страница:

<p:messages id="messages" closable="true" 
    rendered="#{not userController.dialogChangePasswordOpened}" />

<h:form id="formUserData">
    <p:outputPanel styleClass="panelGrey">
        <!-- User data... -->

        <p:panelGrid styleClass="noBorders">
            <p:row>
                <p:column styleClass="colLabel">
                    <p:outputLabel id="labelChangePassword" for="changePassword"
                        value="#{msg['label.password']}"></p:outputLabel>
                </p:column>
                <p:column styleClass="colInput">
                    <p:commandButton id="changePassword"
                        value="#{msg['user.changePassword']}" 
                        actionListener="#{userController.openDialogChangePassword}"
                        update="messages formChangePassword">
                    </p:commandButton>
                </p:column>
            </p:row>
        </p:panelGrid>
    </p:outputPanel>
</h:form>


<!-- Dialog change password -->
<h:form id="formChangePassword">
    <p:dialog id="dlgChangePassword" modal="true"
        header="#{msg['user.changePassword.title']}"
        widgetVar="dlgChangePassword" styleClass="popUpPassword" closable="false">

        <p:messages id="messagesDialog" closable="true" autoUpdate="true"
            globalOnly="false" />
        <p:panelGrid styleClass="noBorders" id="panelChangePassword">
            <p:row>
                <p:column>
                    <p:outputLabel id="labelOldPassword" for="oldPassword"
                        value="#{msg['label.oldPassword']}" />
                </p:column>
                <p:column>
                    <p:password id="oldPassword"
                        value="#{userController.oldPassword}" required="true"
                        feedback="false">
                        <p:ajax update="messagesDialog" event="keyup"></p:ajax>
                    </p:password>
                </p:column>
            </p:row>
            <p:row>
                <p:column>
                    <p:outputLabel id="labelNewPassword" for="newPassword"
                        value="#{msg['label.newPassword']}" />
                </p:column>
                <p:column>
                    <p:password id="newPassword"
                        value="#{userController.newPassword}"
                        match="checkNewPassword"
                        required="true" feedback="true">
                    </p:password>
                </p:column>
            </p:row>
            <p:row>
                <p:column>
                    <p:outputLabel id="labelCheckNewPassword" for="checkNewPassword"
                        value="#{msg['label.checkNewPassword']}" />
                </p:column>
                <p:column>
                    <p:password id="checkNewPassword"
                        value="#{userController.newPassword}" required="true"
                        feedback="false">
                    </p:password>
                </p:column>
            </p:row>
            <p:row>
                <p:column rowspan="2">
                    <p:commandButton id="btnOK" value="#{msg['button.ok']}"
                        update="messages messagesDialog"
                        actionListener="#{userController.changePassword}">
                    </p:commandButton>
                    <p:commandButton id="btnCancel"
                        value="#{msg['button.cancel']}" immediate="true"
                        actionListener="#{userController.closeDialogChangePassword}" />
                </p:column>
            </p:row>
        </p:panelGrid>
    </p:dialog>
</h:form>

Пользовательский контроллер:

private boolean dialogChangePasswordOpened;

public boolean isDialogChangePasswordOpened() {
    return dialogChangePasswordOpened;
}

public void setDialogChangePasswordOpened(boolean dialogChangePasswordOpened) {
    this.dialogChangePasswordOpened = dialogChangePasswordOpened;
}

public void openDialogChangePassword() {
    dialogChangePasswordOpened = true;
    resetChangePasswordFields();
    RequestContext.getCurrentInstance().execute("PF('dlgChangePassword').show()");
}

public void closeDialogChangePassword() {
    dialogChangePasswordOpened = false;
    resetChangePasswordFields();
    RequestContext.getCurrentInstance().execute("PF('dlgChangePassword').hide()");
}

public void resetChangePasswordFields() {
    this.newPassword = "";
    this.oldPassword = "";
}

public void changePassword(ActionEvent actionEvent){
    try{
        usuarioService.changePassword(this.userAuthenticated.getName(),this.oldPassword, this.newPassword);
        FacesContext.getCurrentInstance().addMessage("messages",
                new FacesMessage(FacesMessage.SEVERITY_INFO,
                        "Password has been changed correctly.", null));
        closeDialogChangePassword();
    } catch (Exception e) {
        FacesContext.getCurrentInstance().addMessage("messagesDialog",
                new FacesMessage(FacesMessage.SEVERITY_ERROR,
                        "Error while changing the password.", null));
    }
}

Спасибо.


person Víctor Pariente    schedule 11.06.2015    source источник
comment
Вот как работает messages: он глобальный для всех FacesMessages в очереди. Если вы хотите нацелить свои сообщения, вы должны использовать message, указав идентификатор, когда вы ставите сообщения в очередь.   -  person kolossus    schedule 11.06.2015


Ответы (4)


Вы должны обновлять только те сообщения, которые хотите отобразить: в настоящее время вы делаете 'update="messages messagesDialog"' должно быть update="messagesDialog"

person bwright    schedule 11.06.2015
comment
Спасибо @bwright, но у меня это не работает. Моя проблема в том, что необходимые валидаторы показывают ошибку. - person Víctor Pariente; 11.06.2015
comment
пробовали ли вы ‹p:message for=oldPassword /› как в primefaces.org/ showcase/ui/message/messages.xhtml - person bwright; 11.06.2015
comment
Да, но сообщение по-прежнему появляется в p:messages с id=messages. - person Víctor Pariente; 11.06.2015

Вы должны попробовать добавить globalOnly="true" к p:messages с id="messages". Вы можете удалить globalOnly для p:messages внутри вашего диалогового окна, потому что по умолчанию оно все равно равно false.

Чтобы это работало, измените

FacesContext.getCurrentInstance().addMessage("messages",
                new FacesMessage(FacesMessage.SEVERITY_INFO,
                        "Password has been changed correctly.", null));

к этому:

FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO,
                        "Password has been changed correctly.", null));

Установка нулевого значения для первого параметра (идентификатор компонента) означает, что сообщение будет глобальным и будет перехватываться p:messages с globalOnly="true".

Удачи!

person ochiboy    schedule 11.06.2015
comment
Спасибо @ochiboy, но теперь у меня проблема с ошибками в обязательных полях. Они показаны в двух компонентах сообщений. - person Víctor Pariente; 11.06.2015
comment
Попробуйте изменить атрибут обновления, чтобы обновлять только компоненты внутри диалогового окна. Вы должны исключить обновление компонентов вне диалогового окна, когда оно отображается - person ochiboy; 12.06.2015

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

В вашем диалоге вы бы сделали что-то вроде этого:

<p:messages id="messagesDialog1" autoUpdate="true" for="oldPassword" />
<p:messages id="messagesDialog2" autoUpdate="true" for="newPassword" />
<p:messages id="messagesDialog3" autoUpdate="true" for="checkNewPassword" />

Обратите внимание, что у вас нет «универсальной» корзины, но они все равно будут выглядеть правильно для пользователя, поскольку все они будут прямо друг под другом в любом порядке приоритета, который вы сочтете нужным.

На самой странице у вас все еще есть сообщения, попадающие в общий список, но вам придется обновить его специально. Мне нравится разделять мой между гроулером и окнами сообщений следующим образом:

<p:growl id="growler" showDetail="true" autoUpdate="false" sticky="false" severity="info,warn" />
<p:messages id="messages" showDetail="true" autoUpdate="false" closable="true" severity="error,fatal" />

Затем в компонентах, когда я обрабатываю действие, которое может генерировать сообщение об ошибке, я просто обновляю их:

<p:commandButton value="Do something" action=#{something.fun} update="myPanel growler messages" />

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

Надеюсь, это поможет.

person FreedomRings    schedule 29.07.2015

Используйте redisplay="false" в p:messages на главной странице. Но чтобы это работало, ваши диалоги должны быть включены перед p:message страницы.

Вы можете использовать шаблон, чтобы определить область для размещения всех диалогов и установить их с помощью ui:define.

Шаблон:

<ui:insert name="dialogs"/>
<p:messages autoUpdate="true"  redisplay="false" id="msgs" showDetail="true" showSummary="false" closable="true"/>
<ui:insert name="content" />

Страница:

<ui:define name="dialogs">
 .... include your dialogs here .....
</ui:define>
<ui:define name="content">
 <h:form>
    ...
 </h:form>
</ui:define>

см. эту ссылку: Don't t повторно отображать сообщения, уже показанные в диалоговом окне в ‹p:messages autoUpdate=true›

person Tiago PC    schedule 11.04.2016