Wednesday, February 12, 2014

JSF 2.2 Tip of the Day: Using JSF AJAX Events

Please wait...

Introduction

The JSF framework provides an easy to use AJAX event handling mechanism. The jsf.js library is included in Mojarra and MyFaces. There are two particular methods of interest: jsf.ajax.addOnError(callback) and jsf.ajax.addOnEvent(callback). I will be covering the latter handler.

The JsDoc does not really explain the jsf.ajax.addOnEvent(callback) code very well. Since it is Javascript, you can read it, but I think a simple example of its flexibility with some comments might work better.

Using the addOnEvent is very simple. You register the callback, and it gets called during the lifecycle. The important thing here to remember is that the callback must be a function. Otherwise, it will throw an error. You can control what event processing occurs during the lifecycle.

Events

The callback is invoked during the AJAX request and response lifecycle. The status passed to the callback are listed below.

Event Description
begin This is the start of the AJAX request.
complete This is invoked right after AJAX response is returned.
success This is invoked right after successful processing of AJAX response and update of HTML DOM.


Based on the status, we can take appropriate action on the AJAX event. A great example to demonstrate AJAX event handling is to provide feedback to the user to indicate the status of their request. I will demonstrate how to create an AJAX based progress loader to demonstrate the events.

Code

The code for our AJAX loader is very simple, and could be moved into a composite component if necessary. The NetBeans developed Maven project can be downloaded from the references section below.

index.xhtml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>AJAX Loader Example</title>
        <h:outputStylesheet library="css" name="loader.css"/>
        <h:outputScript library="javax.faces" name="jsf.js" target="head"/>
    </h:head>
    <h:body>
        <h:form>
            <h:commandButton value="Submit" action="#{indexBean.sleep()}">
                <f:ajax execute="@form"/>
            </h:commandButton>
        </h:form>
        <div class="modal">
<!-- Place at bottom of page before JS --></div>
<script type="text/javascript">
            function handleAjax(data) {
                var status = data.status;
 
                switch (status) {
                    case "begin":
                        // This is the start of the AJAX request.
                        document.getElementsByTagName('body')[0].className = 'loading';
                        break;
 
                    case "complete":
                        // This is invoked right after AJAX response is returned.
                        break;
 
                    case "success":
                        // This is invoked right after successful processing of AJAX response and update of HTML DOM.
                        document.getElementsByTagName('body')[0].className = '';
                        break;
                }
            }
            // Setup the statusUpdate function to hear all events on the page
            jsf.ajax.addOnEvent(handleAjax);
        </script>
    </h:body>
</html>

This code controls our progress bar by making changes to the CSS in DOM. The CSS idea is not mine, but it is clever. Here is the CSS.

loader.css


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/* Start by setting display:none to make this hidden.
 * Then we position it in relation to the viewport window
 * with position:fixed. Width, height, top and left speak
 * speak for themselves. Background we set to 80% white with
 * our animation centered, and no-repeating
*/
.modal {
    display:    none;
    position:   fixed;
    z-index:    1000;
    top:        0;
    left:       0;
    height:     100%;
    width:      100%;
    background: rgba( 255, 255, 255, .8 );
    background-image: url('#{facesContext.externalContext.requestContextPath}/resources/images/ajax-loader.gif');
    background-position: 50% 50%;
    background-repeat: no-repeat;
}
 
/* When the body has the loading class, we turn
 * the scrollbar off with overflow:hidden
*/
body.loading {
    overflow: hidden;  
}
 
/* Anytime the body has the loading class, our
 * modal element will be visible
*/
body.loading .modal {
    display: block;
}

A simple CSS layout, and our Javascript callback to jsf.ajax.addOnEvent(callback) is all it takes to make a cool progress loader.

References

Popular Posts