p:wizard 带进度条

p:wizard with a progress bar

我想用两个 PrimeFaces 组件创建注册表单:Wizard and Progress Bar。对于支持 bean,我使用以下一个:

支持 bean:UserWizard.xhtml

import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

import org.primefaces.context.RequestContext;
import org.primefaces.event.FlowEvent;

    @ViewScoped
    @Named
    public class UserWizard implements Serializable {

        private User user = new User();

        private boolean skip;

        private Integer progress = 0;

        public User getUser() {
            return user;
        }

        public void setUser(User user) {
            this.user = user;
        }

        public void save() {        
            FacesMessage msg = new FacesMessage("Successful", "Welcome :" + user.getFirstname());
            FacesContext.getCurrentInstance().addMessage(null, msg);
        }

        public boolean isSkip() {
            return skip;
        }

        public void setSkip(boolean skip) {
            this.skip = skip;
        }

        public String onFlowProcess(FlowEvent event) {
            String oldStep = event.getOldStep();
            Integer oldValue = getStepNumber(oldStep);
            String newStep = event.getNewStep();
            Integer newValue = getStepNumber(newStep);
            if(oldValue < newValue)
               progress += 25;
            else
               progress += 25;

            return event.getNewStep();
}

public Integer getStepNumber(String Step) {
    Integer StepNumber;
    switch(Step) {
        case "personal":
            StepNumber = 1;
            break;
        case "address":
            StepNumber = 2;
            break;
        case "contact":
            StepNumber = 3;
            break;
        default:
            StepNumber = 4;
            break;
    }   
    return StepNumber;
}

        public Integer getProgress() {
            return progress;
        }

        public void setProgress(Integer progress) {
            this.progress = progress;
        }

        public void onComplete() {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Progress Completed"));
        }

        public void cancel() {
            progress = null;
        }
    }

报名表:registration.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:p="http://primefaces.org/ui"
    xmlns:h="http://xmlns.jcp.org/jsf/html">
<body>
    <f:view contracts="#{view.locale.language}">
        <ui:composition template="/template.xhtml">
            <ui:define name="centralBody">
<h:form>

<p:growl id="growl" sticky="true" showDetail="true"/>

<p:wizard flowListener="#{userWizard.onFlowProcess}">
    <p:tab id="personal" title="Personal">
        <p:panel header="Personal Details">
            <p:messages />
            <h:panelGrid columns="2" columnClasses="label, value">
                <h:outputText value="Firstname: *" />
                <p:inputText value="#{userWizard.user.firstname}" required="true" label="Firstname"/>

                <h:outputText value="Lastname: *" />
                <p:inputText value="#{userWizard.user.lastname}" required="true" label="Lastname"/>

                <h:outputText value="Age: " />
                <p:inputText value="#{userWizard.user.age}" />

                <h:outputText value="Skip to last: " />
                <h:selectBooleanCheckbox value="#{userWizard.skip}" />
            </h:panelGrid>
        </p:panel>
    </p:tab>

    <p:tab id="address" title="Address">
        <p:panel header="Address Details">
            <p:messages />
            <h:panelGrid columns="2" columnClasses="label, value">
                <h:outputText value="Street: " />
                <p:inputText value="#{userWizard.user.street}" />

                <h:outputText value="Postal Code: " />
                <p:inputText value="#{userWizard.user.postalCode}" />

                <h:outputText value="City: " />
                <p:inputText value="#{userWizard.user.city}" />

                <h:outputText value="Skip to last: " />
                <h:selectBooleanCheckbox value="#{userWizard.skip}" />
            </h:panelGrid>
        </p:panel>
    </p:tab>

    <p:tab id="contact" title="Contact">
        <p:panel header="Contact Information">
            <p:messages />
            <h:panelGrid columns="2" columnClasses="label, value">
                <h:outputText value="Email: *" />
                <p:inputText value="#{userWizard.user.email}" required="true" label="Email"/>

                <h:outputText value="Phone: " />
                <p:inputText value="#{userWizard.user.phone}"/>

                <h:outputText value="Additional Info: " />
                <p:inputText value="#{userWizard.user.info}"/>
            </h:panelGrid>
        </p:panel>
    </p:tab>

    <p:tab id="confirm" title="Confirmation">
        <p:panel header="Confirmation">
            <h:panelGrid id="confirmation" columns="3" columnClasses="grid,grid,grid">
                <h:panelGrid columns="2" columnClasses="label, value">
                    <h:outputText value="Firstname: " />
                    <h:outputText value="#{userWizard.user.firstname}" styleClass="outputLabel"/>

                    <h:outputText value="Lastname: " />
                    <h:outputText value="#{userWizard.user.lastname}" styleClass="outputLabel"/>

                    <h:outputText value="Age: " />
                    <h:outputText value="#{userWizard.user.age}" styleClass="outputLabel"/>
                </h:panelGrid>

                <h:panelGrid columns="2" columnClasses="label, value">
                    <h:outputText value="Street: " />
                    <h:outputText value="#{userWizard.user.street}" styleClass="outputLabel"/>

                    <h:outputText value="Postal: " />
                    <h:outputText value="#{userWizard.user.postalCode}" styleClass="outputLabel"/>

                    <h:outputText value="City: " />
                    <h:outputText value="#{userWizard.user.city}" styleClass="outputLabel"/>
                </h:panelGrid>

                <h:panelGrid columns="2" columnClasses="label, value">
                    <h:outputText value="Email: " />
                    <h:outputText value="#{userWizard.user.email}" styleClass="outputLabel"/>

                    <h:outputText value="Phone " />
                    <h:outputText value="#{userWizard.user.phone}" styleClass="outputLabel"/>

                    <h:outputText value="Info: " />
                    <h:outputText value="#{userWizard.user.info}" styleClass="outputLabel"/>

                    <h:outputText />
                    <h:outputText />
                </h:panelGrid>
            </h:panelGrid>

            <p:commandButton value="Submit" actionListener="#{userWizard.save}" update="growl" process="@this"/>
        </p:panel>
    </p:tab>
</p:wizard>
<p:progressBar id="progressBar" widgetVar="pbAjax" ajax="true" value="#{UserWizard.progress}" labelTemplate="{value}%" styleClass="animated" global="false">
        <p:ajax event="complete" listener="#{UserWizard.onComplete}" update="growl" oncomplete="PF('startButton2').enable()"/>
    </p:progressBar>
</h:form>
        </ui:define>
        </ui:composition>
    </f:view>
</body>
</html>

我的目的是,当注册流程经过不同的注册选项卡(个人、地址、联系人和确认)时,屏幕下方的进度条会根据下一步或后退按钮进行更新.为了实现这一点,我想使用方法

public String onFlowProcess(FlowEvent event) {
    String oldStep = event.getOldStep();
    Integer oldValue = getStepNumber(oldStep);
    String newStep = event.getNewStep();
    Integer newValue = getStepNumber(newStep);
    if(oldValue < newValue)
        progress += 25;
    else
        progress -= 25;

    return event.getNewStep();
}

public Integer getStepNumber(String Step) {
    Integer StepNumber;
    switch(Step) {
        case "personal":
            StepNumber = 1;
            break;
        case "address":
            StepNumber = 2;
            break;
        case "contact":
            StepNumber = 3;
            break;
        default:
            StepNumber = 4;
            break;
    }   
    return StepNumber;
}

但是不知道怎么更新进度条。我试过:

因为向导(至少 in/upto PrimeFaces 6.0)在使用 flowListener 时似乎不支持 update 属性,并且不支持显式 ajax 事件,我看到的唯一选择是使用 PrimeFaces RequestContext 更新其他组件。请记住,您需要对元素使用 'full absolute path',因此包括它所在的命名容器的所有 ID。然后最好将 ID 显式分配给所有命名容器(包括表单!)

所以使用

RequestContext.getCurrentInstance().update("formId:progress_bar");

例如

public String onFlowProcess(FlowEvent event) {
    String oldStep = event.getOldStep();
    Integer oldValue = getStepNumber(oldStep);
    String newStep = event.getNewStep();
    Integer newValue = getStepNumber(newStep);
    if(oldValue < newValue)
        progress += 25;
    else
        progress -= 25;

    RequestContext.getCurrentInstance().update("formId:progress_bar");        

    return event.getNewStep();
}

在 flowListener 中应该可以工作。请记住,在 bean 的更新中,不需要“:”作为绝对路径的前缀,它们被假定为始终是绝对的