Richfaces - Modal Panel As A Wizard

Richfaces 'Modal Panel' component can be used to create a 'Dialog Box' or a 'Wizard' (or Wizard like behaviour), which is useful, when some part of the website/application has to ask for the input from the user, in steps. It can be customized, as per the requirements of that particular application, although everything that you implement doesn't sound like a standard mechanism, from the 'Richfaces' AJAX framework. Below is an example of creating a 'Wizard' out of a 'Richfaces Modal Panel' component:

1) Lets suppose that this 'Wizard' is opened, when a user clicks on some link (or any other AJAX/Javascript event)...and 2 steps, for that Wizard. So, the modal panel is on one page and there would be 2 other pages that are to be included, in the modal panel, to get that 'Wizard' like behavior. In my case, I'm using JSF and Facelets (Xhtml files). Below is a code snippet for the main page (where the modal panel is included):

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j">

<ui:composition>
...........
...........
............

<rich:modalPanel id="panel1">
<f:facet name="header">
<h:outputText value="Test" />
</f:facet>

<f:facet name="controls">
<h:commandLink value="Close"
style="cursor:pointer"
onclick="Richfaces.hideModalPanel('panel1')" />
</f:facet>

<a4j:include binding="#{someBean.include}" viewId="/view/include1.xhtml"/>
</rich:modalPanel>
</ui:composition>
</html>


2) And below is the code snippet, for the first included page, on the modal panel:

<!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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j">

<ui:composition>
...........
...........
............

<h:form>
<h:panelGrid columns="2">
<h:outputText value="#{msg.input}"
<h:inputText value="#{someBean.someText}"/>

<rich:spacer width="20"/>
<a4j:commandButton value="#{msg.submit}" action="include2" reRender="wizard"/>
</h:panelGrid>
</h:form>
</ui:composition>
</html>


Note that the above included page, doesn't need to have f:view tags. Also, there are a couple of important points to consider from the Richfaces documentation:

RichFaces allows to organize a page flow inside the component. This is a typical scenario for Wizard like behavior. The new content is rendered inside the area. The content is taken from the navigation rule of the faces configuration file (usually, the faces-config.xml). Note, that the content of the "wizard" is not isolated from the rest of the page. The included page should not have own (it does not matter if you use facelets). You need to have an Ajax component inside the to navigate between the wizard pages. Otherwize, the whole page update will be performed.

If you want to involve the server side validators and navigate to the next page only if the Validation phase is passed successfully, you can replace with and point to the action method that navigates to the next page. If Validation process fails, the partial page update will occur and you will see an error message. Otherwize, the application proceeds to the next page. Make sure, you define option for the navigation rule to avoid memory leaks.


3) And below is the "include2.xhtml", which is shown as a second step, for that wizard. This wizard appears only if the validation succeeds on the previously included page (in case, if you have any input validations).

<!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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j">

<ui:composition>
...........
...........
............

<h:form>
<a4j:commandButton value="#{msg.confirm}" action="#{someBean.doSomeBusinessShit}" reRender="someId,wizard"/>
<a4j:commandButton value="#{msg.cancel}" action="#{someBean.reset}" onclick="javascript:Richfaces.hideModalPanel('panel1')" reRender="wizard"/>
</h:form>
</ui:composition>
</html>


4) And the faces-config.xml configuration, is as follows:

<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
............
............
............

<navigation-rule>
<from-view-id>/view/include1.xhtml</from-view-id>
<navigation-case>
<from-outcome>include2</from-outcome>
<to-view-id>/view/include2.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>



...And hey, its not yet over. If you happened to implement the above stuff and if you navigated to the second step, clicked 'Cancel' and tried to open the 'Wizard' again, the second included page, opens up directly, without the first step (included page). To remedy this, I've to reset the "viewId" in the "a4j:include" component. The "a4j:include" tag, already includes a binding. The only thing that has to be done is to implement the "reset" method, as below:

package echo;

import org.ajax4jsf.component.html.Include;

public class SomeBean {
.........
.........
private Include include;

.......
.......
.......

public void reset() {
include.setViewId("/view/include1.xhtml");
}
}

20 comments:

  1. Very useful explanation of the concept..I only have ne request. if you could put working example in there, it would make it even easier to comprehend..anyway thanks for the effort

    ReplyDelete
  2. Please post working example if possible.

    ReplyDelete
  3. Hi,

    Where is called the method reset?

    Wouldn't the method reset have to finish with parenthesis?

    ReplyDelete
  4. Hi Erik,
    Sorry for the late response (I was on vacation). Well, this reset method is in the bean, that manages the functionality of the Wizard (modal panel)...and yes, the braces (not parenthesis) are missing. Thanks for pointing that! :)

    ReplyDelete
  5. Hi Erik,
    Nice example. I have a couple questions. Where is the "wizard" id defined that both include pages refere to reRender in the buttons? Is there a trick to Resolving the ajax4jsf Include import? I cant seem to get the org.ajax4jsf.component.html.Include line to resolve in my project.

    ReplyDelete
  6. Hi Jack,
    It's not Erik, who posted this article. He just commented on this post.

    Regarding your question..Are you sure that you added richfaces jar files, to your libraries? I just checked my code again and I'm using the same import:

    import org.ajax4jsf.component.html.Include;

    ReplyDelete
  7. Sorry Chetty, I'm still a novice Java programmer. I am using IntelliJ deploying to JBoss 5.1 and Seam 2.1.1 using maven. As far as I know the richfaces libraries are part of the seam or JBoss libraries. When I look at my exploded ear I see the Richfaces-api jar in the lib folder. I tried adding a reference to the a4j dependency in my POM file but IntelliJ still could not resolve the Include object. I was really strugling with the a4j:include with simple pages no bean interaction and I found my issue with the include was I had not put a slash in front of the viewid so faces-config was not picking up my navigation rule even though the first included page was rendering fine. It just wouldn't do anything when I selected on my button. All the pages were in the same directory so I didn't know I needed the slash.

    ReplyDelete
  8. Hi Chetty,
    i have the same question with Bower:
    where is "wizard" ?? i couldn't resolve :(

    ReplyDelete
  9. PrimeFaces has a dedicated wizard component. http://www.primefaces.org:8080/prime-showcase/ui/wizard.jsf

    You can also place it in PrimeFaces dialog.

    ReplyDelete
  10. Hello Ozan,
    What do you mean by "where is 'wizard'"? ...

    Anyways.....This post is about using Richfaces Modal Panel to simulate a Wizard like behaviour. Check the tag.

    ReplyDelete
  11. I mean, check the tag rich:modalPanel

    ReplyDelete
  12. Can you provide sample working example ?

    ReplyDelete
  13. Hi, Greart Post but the solution doesn't work. Navigation from page1 to page2 fails and the modal panel closes.

    Think togglePanel may work.

    Thanks

    ReplyDelete
  14. Hello Anonyomous Person,

    I have posted this solution, only after implementing this in one of my projects...I don't know why it fails for you..keep trying! ;)

    ReplyDelete
  15. i have problem to reset the page . Eventhought i setViewId to first page and rerender the wizard . Any idea why ?

    My code :
    a4j:commandButton action="#{asManager.cancelBtn}" reRender="CreatePage" oncomplete="#{rich:component('panelCreate')}.hide();" value="cancel"


    public String cancelBtn(){ FacesContext.getCurrentInstance().getExternalContext().getRequestMap().remove("asManager");

    jspInclude.setViewId("/pages/AutoScale/ASCreatePage1.jsp");

    return "";
    }

    ReplyDelete
  16. Hello tee,
    I have limited information from your comment, to judge whats wrong with your code. I can't exactly tell, unless you post some more code snippets (like I posted).

    ReplyDelete
  17. Hello,
    i implemented something very similar to this post (How to organize wizards using the rich:modalPanel component) using the ideas specified on this URL: //www.jboss.org/file-access/default/members/jbossrichfaces/freezone/docs/devguide/en/faq/faq.html
    but it did not work. When i click at the Next button of the first included page nothing happens. Does anybody know why?

    Carlos Soares

    ReplyDelete
  18. I have the same question: where is "wizard" ?? i also couldn't resolve.

    Renata

    ReplyDelete
  19. I have the same question: where is "wizard" ?? i also couldn't resolve.

    Renata

    ReplyDelete
  20. thanks for the example. I could get it working. I think the missing point is the "wizard"-id in
    <a4j:include id="wizard" binding="#{someBean.include}" viewId="/view/include1.xhtml"/>

    ReplyDelete

Note: Only a member of this blog may post a comment.