Multiple PrimeFaces dialogs on one page

2019-04-18 02:01发布

问题:

I am facing problems with dialog windows validation. On home.xhtml I have a tabview with 3 nested dataTables and CRUD buttons (see screenshot). Every button is supposed to call a dialog window with a form to add/edit entity. But whenever I fail to validate some field in any form - all other forms are displayed too:

I would like to validate and display only one dialog at a time and keep it displayed untill user presses "Cancel" button or inputs valid values and presses submit button. No other dialogs shold be opened at this time.

home.xhtml:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:component xmlns="http://www.w3.org/1999/xhtml"
              xmlns:h="http://xmlns.jcp.org/jsf/html"
              xmlns:p="http://primefaces.org/ui"
              xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
              xmlns:f="http://java.sun.com/jsf/core"
              xmlns:ex="http://java.sun.com/jsf/composite/nsobchuk">
    <h:head>
        <link rel="stylesheet" href="../css/style.css"/>
    </h:head>

    <h:body>

        <h:form id="logout" class="logout" >
            <h:commandButton action="#{loginBean.logout()}" value="logout"/>
        </h:form>

        <p:tabView id="tab" orientation="left">

            <p:tab title="Users">

                <h:form id="form1">

                    <h:panelGrid columns="9">

                        <p:commandButton type="button" value="Add" onclick="dlg1.show()"/>


                        <p:commandButton id="editUser" type="button" value="Edit" onclick="dlg2.show()" disabled="#{homeBean.selectedUser == null}"/>
                        <p:dialog id="editUserDialogerDialog" widgetVar="dlg2" header="Sorry" >
                            <h:outputText value="I didn't have enogh time to finish this functionality. Feel free to test other buttons."/>
                        </p:dialog>


                        <p:commandButton id="deleteUser" type="button" onclick="confirmation1.show()" value="Delete" disabled="#{homeBean.selectedUser == null}"/>
                        <p:confirmDialog message="Are you sure you want to delete user?" header="Confirmation"
                                         severity="alert" widgetVar="confirmation1">
                            <p:commandButton value="Yes" update=":tab:users" process="@this" styleClass="ui-confirmdialog-yes" icon="ui-icon-check"
                                             oncomplete="confirmation1.hide()" action="#{homeBean.deleteUser}" />
                            <p:commandButton value="No" onclick="confirmation1.hide()" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close"/>
                        </p:confirmDialog>

                    </h:panelGrid>

                </h:form>


                <p:dataTable id="users" var="user" value="#{homeBean.users}" 
                             scrollable="true" scrollHeight="250" selectionMode="single"
                             selection="#{homeBean.selectedUser}" rowKey="#{user.userId}"
                             sortMode="single">

                    <p:ajax event="rowSelect" listener="#{homeBean.onUserRowSelect}" update=":tab:form1:deleteUser, :tab:form1:editUser"/> 
                    <p:ajax event="rowUnselect" listener="#{homeBean.onUserRowUnselect}" update=":tab:form1:deleteUser, :tab:form1:editUser"/>

                    <p:column headerText="Login" sortBy="#{user.login}">  
                        <h:outputText value="#{user.login}"/>
                    </p:column>

                    <p:column headerText="Password" sortBy="#{user.password}">  
                        <h:outputText value="#{user.password}"/>
                    </p:column>

                    <p:column headerText="Role" sortBy="#{user.role}">  
                        <h:outputText value="#{user.role}"/>
                    </p:column>

                    <p:column headerText="Name" sortBy="#{user.firstName}">  
                        <h:outputText value="#{user.firstName}"/>
                    </p:column>

                    <p:column headerText="Surname" sortBy="#{user.lastName}">  
                        <h:outputText value="#{user.lastName}"/>
                    </p:column>

                </p:dataTable>

                <ex:exporter target=":tab:users" fileName="Users"/>

            </p:tab>

            <p:tab title="Computers">

                <h:form id="form2">

                    <h:panelGrid columns="9">

                        <p:commandButton type="button" value="Add" onclick="dlg3.show()"/>


                        <p:commandButton id="editComp" type="button" value="Edit" onclick="dlg4.show()" disabled="#{homeBean.selectedComputer == null}"/>
                        <p:dialog id="editCompDialog" widgetVar="dlg4" header="Sorry" >
                            <h:outputText value="I didn't have enogh time to finish this functionality. Feel free to test other buttons."/>
                        </p:dialog>


                        <p:commandButton id="deleteComp" type="button" onclick="confirmation2.show()" value="Delete" disabled="#{homeBean.selectedComputer == null}"/>
                        <p:confirmDialog message="Are you sure you want to delete this computer?" header="Confirmation"
                                         severity="alert" widgetVar="confirmation2">
                            <p:commandButton value="Yes" update=":tab:computers" process="@this" styleClass="ui-confirmdialog-yes" icon="ui-icon-check"
                                             oncomplete="confirmation2.hide()" action="#{homeBean.deleteComputer}"/>
                            <p:commandButton value="No" onclick="confirmation2.hide()" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close"/>
                        </p:confirmDialog>

                    </h:panelGrid>

                </h:form>


                <p:dataTable id="computers" var="computer" value="#{homeBean.computers}" 
                             scrollable="true" scrollHeight="250" selectionMode="single"
                             selection="#{homeBean.selectedComputer}" rowKey="#{computer.computerId}"
                             sortMode="single" >
                    <p:ajax event="rowSelect" listener="#{homeBean.onCompRowSelect}" update=":tab:form2:editComp, :tab:form2:deleteComp"/> 

                    <p:column headerText="Login" sortBy="#{computer.login}">  
                        <h:outputText value="#{computer.login}"/>  
                    </p:column>

                    <p:column headerText="Password" sortBy="#{computer.password}">  
                        <h:outputText value="#{computer.password}"/>  
                    </p:column>

                    <p:column headerText="Name" sortBy="#{computer.computerName}" > 
                        <h:outputText value="#{computer.computerName}"/>  
                    </p:column>

                    <p:column headerText="IP address" sortBy="#{computer.ipAddress}">  
                        <h:outputText value="#{computer.ipAddress}"/>  
                    </p:column>

                </p:dataTable>

                <ex:exporter target=":tab:computers" fileName="Computers"/>

            </p:tab>

            <p:tab title="Applications">


                <h:form id="form3">

                    <h:panelGrid columns="9">

                        <p:commandButton type="button" value="Add" onclick="dlg5.show()"/>




                        <p:commandButton id="editApp" type="button" value="Edit" onclick="dlg6.show()" disabled="#{homeBean.selectedApplication == null}"/>
                        <p:dialog id="editAppDialog" widgetVar="dlg6" header="Sorry" >
                            <h:outputText value="I didn't have enogh time to finish this functionality. Feel free to test other buttons."/>
                        </p:dialog>


                        <p:commandButton id="deleteApp" type="button" onclick="confirmation3.show()" value="Delete" disabled="#{homeBean.selectedApplication == null}"/>
                        <p:confirmDialog message="Are you sure you want to delete this application?" header="Confirmation"
                                         severity="alert" widgetVar="confirmation3">
                            <p:commandButton value="Yes" update=":tab:applications" process="@this" styleClass="ui-confirmdialog-yes" icon="ui-icon-check"
                                             oncomplete="confirmation3.hide()" action="#{homeBean.deleteApplication}"/>
                            <p:commandButton value="No" onclick="confirmation3.hide()" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close"/>
                        </p:confirmDialog>

                    </h:panelGrid>

                </h:form>

                <p:dataTable id="applications" var="app" value="#{homeBean.applications}" 
                             scrollable="true" scrollHeight="250" selectionMode="single"
                             selection="#{homeBean.selectedApplication}" rowKey="#{app.appId}"
                             sortMode="single" >

                    <p:ajax event="rowSelect" listener="#{homeBean.onAppRowSelect}" update=":tab:form3:editApp, :tab:form3:deleteApp"/>

                    <p:column headerText="Name" sortBy="#{app.appName}">  
                        <h:outputText value="#{app.appName}"/>  
                    </p:column>

                    <p:column headerText="Vendor" sortBy="#{app.vendorName}" >  
                        <h:outputText value="#{app.vendorName}"/>  
                    </p:column>

                    <p:column headerText="License required" sortBy="#{app.licenseRequired}">  
                        <h:outputText value="#{app.licenseRequired}"/>  
                    </p:column>

                </p:dataTable>

                <ex:exporter target=":tab:applications" fileName="Applications" />

            </p:tab>

        </p:tabView>





        <h:form id="dlg1form">
            <p:dialog id="addUserDialog" header="Add Dialog" modal="true" closable="false"
                      widgetVar="dlg1" width="620" visible="#{facesContext.validationFailed}" >

                <h:panelGrid columns="3">

                    <h:outputLabel for="login" value="Login: "/>
                    <p:inputText id="login" value="#{homeBean.newUser.login}" required="true"  
                                 label="Login: " maxlength="20">
                        <f:validator binding="#{loginValidator}"/>
                    </p:inputText>
                    <p:message for="login"/>

                    <h:outputLabel for="password" value="Password: "/>
                    <p:password id="password" value="#{homeBean.newUser.password}" required="true" 
                                feedback="true"  label="Password: " maxlength="32"/>
                    <p:message for="password" />

                    <h:outputLabel for="firstName" value="First Name: "/>
                    <p:inputText id="firstName" value="#{homeBean.newUser.firstName}"
                                 label="First Name: " maxlength="20"/>
                    <p:message for="firstName"/>

                    <h:outputLabel for="lastName" value="Last Name: "/>
                    <p:inputText id="lastName" value="#{homeBean.newUser.lastName}" 
                                 label="Last Name: " maxlength="20"/>
                    <p:message for="lastName"/>

                    <h:outputLabel for="role" value="Role: "/>
                    <p:selectOneMenu id="role" value="#{homeBean.newUser.role}" required="true" style="width: 80px;" >
                        <f:selectItem itemLabel="user" itemValue="ROLE_USER" />
                        <f:selectItem itemLabel="admin" itemValue="ROLE_ADMIN" />
                    </p:selectOneMenu>
                    <p:message for="role"/>

                </h:panelGrid>

                <p:commandButton value="Cancel" immediate="true" onclick="dlg1.hide()" update=":dlg1form:addUserDialog">
                    <p:resetInput target="addUserDialog"  />
                </p:commandButton>

                <p:commandButton value="Add" update=":tab:users, :dlg1form:addUserDialog" process="@this" 
                                 onclick="if (args &amp; &amp; !args.validationFailed) dlg1.hide()" action="#{homeBean.addUser}"/>


            </p:dialog>

        </h:form>


        <h:form id="dlg3form">
            <p:dialog id="addCompDialog" header="Add Dialog" draggable="true" closable="false" modal="true"
                      widgetVar="dlg3" width="600" visible="#{facesContext.validationFailed}">


                <h:panelGrid columns="3">

                    <h:outputLabel for="pclogin" value="Login: "/>
                    <p:inputText id="pclogin" value="#{homeBean.newComputer.login}" required="true"  
                                 label="Login: " maxlength="20">
                        <f:validator binding="#{loginValidator}"/>
                    </p:inputText>
                    <p:message for="pclogin"/>

                    <h:outputLabel for="pcpassword" value="Password: "/>
                    <p:password id="pcpassword" value="#{homeBean.newComputer.password}" required="true" 
                                feedback="true"  label="Password: " maxlength="32"/>
                    <p:message for="pcpassword" />

                    <h:outputLabel for="compName" value="Computer Name: "/>
                    <p:inputText id="compName" value="#{homeBean.newComputer.computerName}" required="true"
                                 label="Computer Name: " maxlength="20"/>
                    <p:message for="compName"/>

                    <h:outputLabel for="ipaddress" value="IP address: "/>
                    <p:inputText id="ipaddress" value="#{homeBean.newComputer.ipAddress}" required="true"
                                 label="IP address: " maxlength="20"/>
                    <p:message for="ipaddress"/>

                </h:panelGrid>

                <p:commandButton value="Cancel" immediate="true" onclick="dlg3.hide()" update=":dlg3form:addCompDialog">
                    <p:resetInput target="addCompDialog" />
                </p:commandButton>

                <p:commandButton value="Add" update=":tab:computers, :dlg3form:addCompDialog" process="@this" 
                                 onclick="if (args &amp; &amp; !args.validationFailed) dlg3.hide()" action="#{homeBean.addComputer}"/>


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

        <h:form id="dlg5form">
            <p:dialog id="addAppDialog" header="Add Dialog" draggable="true" closable="false" modal="true"
                      widgetVar="dlg5" width="600" visible="#{facesContext.validationFailed}">


                <h:panelGrid columns="3">

                    <h:outputLabel for="appName" value="Name: "/>
                    <p:inputText id="appName" value="#{homeBean.newApplication.appName}" required="true"  
                                 label="Name: "/>
                    <p:message for="appName"/>

                    <h:outputLabel for="vendorName" value="Vendor: "/>
                    <p:inputText id="vendorName" value="#{homeBean.newApplication.vendorName}"
                                 label="Vendor: " required="true" />
                    <p:message for="vendorName"/>

                    <h:outputLabel for="appLicense" value="Requires license: "/>
                    <p:selectOneMenu id="appLicense" value="#{homeBean.newApplication.licenseRequired}" required="true" style="width: 80px;" >
                        <f:selectItem itemLabel="True" itemValue="#{true}" />
                        <f:selectItem itemLabel="False" itemValue="#{false}" />
                    </p:selectOneMenu>
                    <p:message for="appLicense"/>

                </h:panelGrid>

                <p:commandButton value="Cancel" immediate="true" onclick="dlg5.hide()" update=":dlg5form:addAppDialog">
                    <p:resetInput target="addAppDialog" />
                </p:commandButton>

                <p:commandButton value="Add" update=":tab:applications, :dlg5form:addAppDialog" process="@this" 
                                 onclick="if (args &amp; &amp; !args.validationFailed) dlg5.hide()" action="#{homeBean.addApplication}"/>


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


    </h:body>

</ui:component>

HomeBean.java:

    package com.infostroy.adminportal.controller.bean;

import com.infostroy.adminportal.bean.BaseBean;
import com.infostroy.adminportal.model.Application;
import com.infostroy.adminportal.model.Computer;
import com.infostroy.adminportal.model.User;
import com.infostroy.adminportal.service.HibernateDBManager;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import org.primefaces.context.RequestContext;
import org.primefaces.event.SelectEvent;
import org.primefaces.event.UnselectEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("session")
public class HomeBean extends BaseBean {

    private static final String editUserBtn = "tab:form1:editUser";
    private static final String deleteUserBtn = "tab:form1:deleteUser";
    private static final String editCompBtn = "tab:form2:editComp";
    private static final String deleteCompBtn = "tab:form2:deleteComp";
    private static final String editAppBtn = "tab:form3:editApp";
    private static final String deleteAppBtn = "tab:form3:deleteApp";
    @Autowired
    private HibernateDBManager hibernateDBManager;
    private List<User> users;
    private List<Computer> computers;
    private List<Application> applications;
    private User selectedUser, newUser;
    private Computer selectedComputer, newComputer;
    private Application selectedApplication, newApplication;
    private RequestContext rc;


    @Override
    public void init() {
        setUsers(hibernateDBManager.getAllUsers());
        setComputers(hibernateDBManager.getAllComputers());
        setApplications(hibernateDBManager.getAllApplications());
        newUser = new User();
        newComputer = new Computer();
        newApplication = new Application();
        rc = RequestContext.getCurrentInstance();
    }

    public void addUser() throws NoSuchAlgorithmException {
        if (newUser != null && newUser.getPassword() != null) {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(newUser.getPassword().getBytes());
            String hash = new BigInteger(1, md.digest()).toString(16);
            newUser.setPassword(hash);
            if (hibernateDBManager.insertUser(newUser)) {
                users.add(newUser);
            }
        }
    }

    public void editUser() {
        if (selectedUser != null) {
            hibernateDBManager.updateUser(selectedUser);
            users.set(users.indexOf(selectedUser), selectedUser);
            selectedUser = null;
            rc.update(deleteUserBtn);
            rc.update(editUserBtn);
        }
    }

    public void deleteUser() throws IOException {
        if (selectedUser != null) {
            if (hibernateDBManager.deleteUserById(selectedUser.getUserId()) > 0) {
                users.remove(selectedUser);
                selectedUser = null;
                rc.update(deleteUserBtn);
                rc.update(editUserBtn);
            }
        }
    }

    public void addComputer() {
        if (newComputer != null && hibernateDBManager.insertComputer(newComputer)) {
            computers.add(newComputer);
        }
    }

    public void deleteComputer() {
        if (selectedComputer != null) {
            if (hibernateDBManager.deleteComputerById(selectedComputer.getComputerId()) > 0) {
                computers.remove(selectedComputer);
                selectedComputer = null;
                rc.update(editCompBtn);
                rc.update(deleteCompBtn);
            }
        }
    }

    public void addApplication() {
        if (newApplication != null && hibernateDBManager.insertApplication(newApplication)) {
            applications.add(newApplication);
        }
    }

    public void deleteApplication() {
        if (selectedApplication != null) {
            if (hibernateDBManager.deleteApplicationById(selectedApplication.getAppId()) > 0) {
                applications.remove(selectedApplication);
                selectedApplication = null;
                rc.update(editAppBtn);
                rc.update(deleteAppBtn);
            }
        }
    }


    public void onUserRowSelect(SelectEvent event) {
        setSelectedUser((User) event.getObject());
    }

    public void onUserRowUnselect(UnselectEvent event) {
        setSelectedUser(null);
    }

    public void onCompRowSelect(SelectEvent event) {
        setSelectedComputer((Computer) event.getObject());
    }

    public void onAppRowSelect(SelectEvent event) {
        setSelectedApplication((Application) event.getObject());
    }

    //GETTERS etc.

}

Any ideas how this can be solved? How can I open and keep only one dialog opened untill it is validated? Every answer is highly appreciated. If you need some additional info - let me know and I will respond immidiately. Thank you.

回答1:

I was able to replicate the problem in my environment. In order to do that I've simplified your home.xhtml code (removing the managedbean references) and here is the changes to the dialogs that made them work:

<p:dialog id="addUserDialog" header="Add Dialog" modal="true" closable="false"
          widgetVar="dlg1" width="620" >

    <h:form id="dlg1form">
        <h:panelGrid columns="3">

            <h:outputLabel for="login" value="Login: "/>
            <p:inputText id="login" required="true"  
                         label="Login: " maxlength="20" >

            </p:inputText>
            <p:message for="login"/>

            <h:outputLabel for="password" value="Password: "/>
            <p:password id="password" required="true" 
                        feedback="true"  label="Password: " maxlength="32"/>
            <p:message for="password" />

            <h:outputLabel for="firstName" value="First Name: "/>
            <p:inputText id="firstName" 
                         label="First Name: " maxlength="20"/>
            <p:message for="firstName"/>

            <h:outputLabel for="lastName" value="Last Name: "/>
            <p:inputText id="lastName"
                         label="Last Name: " maxlength="20"/>
            <p:message for="lastName"/>

            <h:outputLabel for="role" value="Role: "/>
            <p:selectOneMenu id="role" required="true" style="width: 80px;" >
                <f:selectItem itemLabel="user" itemValue="ROLE_USER" />
                <f:selectItem itemLabel="admin" itemValue="ROLE_ADMIN" />
            </p:selectOneMenu>
            <p:message for="role"/>

        </h:panelGrid>

        <p:commandButton value="Cancel" immediate="true" onclick="dlg1.hide()" update="@form">
            <p:resetInput target="addUserDialog"  />
        </p:commandButton>

        <p:commandButton value="Add" update="@form" 
                         oncomplete="if (args &amp;&amp; !args.validationFailed) dlg1.hide()" />
    </h:form>
</p:dialog>


<p:dialog id="addCompDialog" header="Add Dialog" draggable="true" closable="false" modal="true"
          widgetVar="dlg3" width="600">

    <h:form id="dlg3form">
        <h:panelGrid columns="3">

            <h:outputLabel for="pclogin" value="Login: "/>
            <p:inputText id="pclogin" required="true"  
                         label="Login: " maxlength="20">
            </p:inputText>
            <p:message for="pclogin"/>

            <h:outputLabel for="pcpassword" value="Password: "/>
            <p:password id="pcpassword" required="true" 
                        feedback="true"  label="Password: " maxlength="32"/>
            <p:message for="pcpassword" />

            <h:outputLabel for="compName" value="Computer Name: "/>
            <p:inputText id="compName" required="true"
                         label="Computer Name: " maxlength="20"/>
            <p:message for="compName"/>

            <h:outputLabel for="ipaddress" value="IP address: "/>
            <p:inputText id="ipaddress" required="true"
                         label="IP address: " maxlength="20"/>
            <p:message for="ipaddress"/>

        </h:panelGrid>

        <p:commandButton value="Cancel" immediate="true" onclick="dlg3.hide()" process="@this" update="@form">
            <p:resetInput target="addCompDialog" />
        </p:commandButton>

        <p:commandButton value="Add" update="@form" 
                         oncomplete="if (args &amp;&amp; !args.validationFailed) dlg3.hide()" />
    </h:form>
</p:dialog>

<p:dialog id="addAppDialog" header="Add Dialog" draggable="true" closable="false" modal="true"
          widgetVar="dlg5" width="600" >
    <h:form id="dlg5form">
        <h:panelGrid columns="3">
            <h:outputLabel for="appName" value="Name: "/>
            <p:inputText id="appName" required="true"  
                         label="Name: "/>
            <p:message for="appName"/>

            <h:outputLabel for="vendorName" value="Vendor: "/>
            <p:inputText id="vendorName" 
                         label="Vendor: " required="true" />
            <p:message for="vendorName"/>

            <h:outputLabel for="appLicense" value="Requires license: "/>
            <p:selectOneMenu id="appLicense" required="true" style="width: 80px;" >
                <f:selectItem itemLabel="True" itemValue="#{true}" />
                <f:selectItem itemLabel="False" itemValue="#{false}" />
            </p:selectOneMenu>
            <p:message for="appLicense"/>
        </h:panelGrid>

        <p:commandButton value="Cancel" immediate="true" onclick="dlg5.hide()" update="@form" process="@this">
            <p:resetInput target="addAppDialog" />
        </p:commandButton>

        <p:commandButton value="Add" update="@form" 
                         oncomplete="if (args &amp;&amp; !args.validationFailed) dlg5.hide()"/>
    </h:form>
</p:dialog> 

Some notes:

  • I've noticed that you where testing validation onclick instead of oncomplete.
  • I've placed the form inside the dialog for no special reason, just habit.
  • I've removed the visible="#{facesContext.validationFailed}" because that won't be necessary.
  • The same happened with the process="@this" on add buttons, see more about Partial Process here.

Consider changing the cancel button logic to something like this:

<p:commandButton value="Cancel" action="#{viewMBean.clearUser}" oncomplete="dlg1.hide()" update="@form" process="@this" />

public void clearUser() {
    newUser = new User();
}