views:

116

answers:

1

I'm using RichFaces component library and I want to manage the history of Ajax navigation, so the enduser can use the browser back and forward buttons.

Is there any clean way to do it, design pattern, library, etc?

+2  A: 

You can use RSH to handle Ajax history

For the example lets assume that you have a page where the user should select a color. Then, the selected color is posted to the server using XmlHttpRequest.

Now we want to restore previous selection when the back and forward navigation buttons is pressed.

Code Example

Bean:

public class Bean {

    private static final String DAFAULT_COLOR = "green";

    private Map<String, Color> colors;
    private Color selectedColor;
    private String restoredColor;

    @PostConstruct
    public void init() {
        this.colors = new HashMap<String, Color>();
        this.colors.put("green", new Color("Green", "008000"));
        this.colors.put("blue", new Color("Blue", "0000FF"));
        this.colors.put("red", new Color("Red", "FF0000"));
        this.colors.put("purple", new Color("Purple", "FF0000"));
        this.colors.put("purple", new Color("Purple", "800080"));
        this.colors.put("yellow", new Color("Yellow", "FFFF00"));
        this.colors.put("silver", new Color("Silver", "C0C0C0"));
        this.colors.put("black", new Color("Black", "000000"));
        this.colors.put("white", new Color("White", "FFFFFF"));

        this.selectedColor = this.colors.get(DAFAULT_COLOR);
    }

    public void setSelectedColor(ActionEvent event) {
        UIComponent component = event.getComponent();
        String color = ((String)component.getAttributes().get("color")).toLowerCase();
        this.selectedColor =  this.colors.get(color);
    }

    public void restoreColor() {
        if(restoredColor.equals("") || restoredColor.equals("null")) {
            restoredColor =  DAFAULT_COLOR; 
        }

        this.selectedColor =  this.colors.get(restoredColor);
    }

    public List<Color> getColors() {
        return Arrays.asList(colors.values().toArray(new Color[0]));
    }

    public Color getSelectedColor() {
        return selectedColor;
    }

    public String getRestoredColor() {
        return restoredColor;
    }

    public void setRestoredColor(String restoredColor) {
        this.restoredColor = restoredColor.toLowerCase();
    }

}

View:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:t="http://myfaces.apache.org/tomahawk"
    xmlns:c="http://java.sun.com/jstl/core"
    xmlns:a4j="http://richfaces.org/a4j"
    xmlns:rich="http://richfaces.org/rich"  
    template="/WEB-INF/template/default.xhtml">

<ui:define name="head">
    <script type="text/javascript" src="#{request.contextPath}/js/rsh/rsh.js"></script>
    <script type="text/javascript">
        window.dhtmlHistory.create({
            toJSON: function(o) {
                return Object.toJSON(o);
            },
            fromJSON: function(s) {
                return s.evalJSON();
            }
        });

        Event.observe(window, 'load', function() {
            dhtmlHistory.initialize();
            dhtmlHistory.addListener(handleHistoryChange);
        });

        var registerHistoryPoint = function(newLocation, historyData) {
            dhtmlHistory.add(newLocation, historyData); 
        };
    </script>
</ui:define>    

<ui:define name="content">
    <a4j:form id="frmColor">
        <div class="colors">
            <ul>
                <a4j:repeat value="#{bean.colors}" var="color">
                    <li style="background:##{color.hex};">
                        <a4j:commandLink value="&#160;"
                            actionListener="#{bean.setSelectedColor}" 
                            reRender="frmColor"
                            oncomplete="registerHistoryPoint('#{color.name}', '#{color.name}');">
                            <f:attribute name="color" value="#{color.name}"/>
                        </a4j:commandLink>
                    </li>
                </a4j:repeat>
            </ul>
        </div>
        <div class="selection" style="background:##{bean.selectedColor.hex};">
            <div class="selected-color" 
                style="color: ##{bean.selectedColor.name eq 'White' or 
                         bean.selectedColor.name eq 'Yellow' ? '000000' : 'ffffff'}">
                <h:outputText value="#{bean.selectedColor.name}"/>
            </div>
        </div>
        <a4j:jsFunction name="handleHistoryChange" reRender="frmColor"
            action="#{bean.restoreColor}">
            <a4j:actionparam name="historyData" assignTo="#{bean.restoredColor}" /> 
        </a4j:jsFunction>
    </a4j:form>
</ui:define>
</ui:composition>

Now when the user click on a color the registerHistoryPoint is invoked. This will register historyData that will be passed to the bean when the back and forward buttons is pressed.

e.g.

  • User select Yellow.
  • Yellow is registered.
  • User select Blue.
  • Blue is registered.
  • User click on back.
  • Yellow is restored.
  • User click forward.
  • Blue is restored.
mmanco
Thank you, I'll be trying it and see if it's works.
imrabti
historyData where it is used ?
imrabti
It will be passed by RSH as an argument to the function e.g. when back button pressed.You should handle this on the server side.
mmanco
What Kind the historyData contain. Is it used to restore the state of the Page. Can you please give a more accurate Example of using it ?
imrabti
Thank, Trying it right Now.
imrabti
Sources of the example available here - http://kernelhost.org/so-examples/ajax-history.rar
mmanco
Thx It saved My Life.
imrabti