Wednesday, December 29, 2010

How to create a stateful Richfaces popup

This article has been published first on Javalobby

I use JSF and especially Richfaces for 1 year. During this year I had a few issues with Richfaces popups.

Richfaces popups had the following issues

  • The popup component is stored in the components tree although it is not displayed. On some use cases, the complete popup sub tree can be stored in the tree.
  • Because popups are usually displayed using javascript, there are not sync with the components tree and vice versa.
  • So popups are display off when user reloads the page, that generates inconsistent state.
  • A lot of popups on the same page, that significates a lot of rich:modalPanel components, increases file size and decreases readability.
  • Popups don't stack easily (A calls B or B calls A mean different zindex for A and B).

One of my coworker said richfaces popup component doesn’t scale because each sort of popup requires a specific declaration. The team had create a JSF fragment file that contains all the popup components whatever their domains or the business logic location in package and module.

My opinion is that a popup should be part of the UI logic. It should not be a component you add like a textbox but it would rather be a window you create with a createPopup method.

Ok let's try to improve popup logic.


First step : Java logic

The first step is to create a popup controller which manage the active popups displayed on the page. The controller is a session bean named popupController that can be wired to any controllers.


The interface will be :
public interface IPopupController {

void add(String uri, IPopupBean bean);

void removeLast();

List<IPopupDescriptor> getPopups();

UIComponent getPopupContainer();

void setPopupContainer(UIComponent popupContainer);
}
The add method will be used to add and display popup.
The following example will display the popup foo.xhtml with the bean fooBean:
popupController.add("foo.xhtml" , fooBean);

Second step : UI logic

The second step is to create the UI logic that will display the popups. This is a simple JSF fragment that contains the UI logic:
<a4j:outputPanel binding="#{popupController.popupContainer}" id="popupContainer">
<c:forEach items="#{popupController.popups}" var="popup">
<f:subview id="popupView#{popup.id}">
<ui:include src="#{popup.uri}">
<ui:param name="popupBean" value="#{popup.popupBean}"/>
</ui:include>
</f:subview>
</c:forEach>
</a4j:outputPanel>

The popups are contained in a <a4j:outputPanel> to allow AJAX refresh. The facelet iterates on the popups managed by the popupController bean. Each popup is in a subview with a custom id to avoid duplicate id exception.

The previous fragment had to be included in all pages that used popups :
<ui:include src="/popup/popup.xhtml"/>
With facelet it is easy to create a page template that will hold this fragment.

To simplify the article it's the user responsibility to create the popup file that should respect the following template :
<rich:modalPanel id="anId" zindex="#{popupBean.popupDescriptor.zIndex}">
[...]
</rich:modalPanel>
<a4j:outputPanel>
<script type="text/javascript">
javascript:Richfaces.showModalPanel('anId')
</script>
</a4j:outputPanel>
The zIndex is computed automatically by the popupController. The javascript ensures at each Ajax refresh or page reload that all popups will be redisplayed.

Finally

With the following article, I show how to improve popup logic that keeps client and server sync. The drawback of this method is it needs a request to be sync with the server. On a low latency network it should not be an issue. But on a medium or high latency it may be different.

I have attached a small Maven war project that contains the code of this article.

What is your opinion ?

4 comments:

  1. when I am trying to run your sample application it is asking me to either open or save the file. After clicking on the open option, it shows nothing.

    Any thought.

    ReplyDelete
  2. Great ...
    How can we support application with several tabs? Are there some problems in this code if someone open several tabs?

    ReplyDelete
  3. My code does not support several tabs. It may be add easily, it depends on the JSF version and JSF impl.

    Have a look at : http://stackoverflow.com/questions/3202604/using-jsf-with-multiple-tabs-in-one-browser

    ReplyDelete