Skip to main content

JSF Tutorial – Add Ajax Support to the Application

Ajax has been used for many years since web 2.0. Its primary goal is to provide a refresh-free experience. Using ajax technology is very easy in JSF, for it integrates javascript library used to implement ajax functionality into a single jsf tag.

Project source code on github

Add Ajax Support

In our notebook project, we can implement adding categories functionality using ajax. Let’s add some code to our index.xhtml page in the notebook module.

Two more libraries are required, jsf core and jstl. The jsf core library will give us the ability to use ajax, and jstl library is used to do some data logic:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:jsf="http://xmlns.jcp.org/jsf"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">

Add the following code before the closing </h:body> tag:

<!-- Add category section -->
<h:form>
    <p>
    <h:outputLabel for="categoryName">Create a new category: </h:outputLabel>
    <h:inputText id="categoryName" value="#{noteBackBean.categoryName}" />
    <h:commandButton action="#{noteBackBean.addCategory}" value="Add">
        <h:outputScript target="head" library="js" name="script.js" />
        <f:ajax render="categories" execute="categoryName" onevent="handleEvent" />
    </h:commandButton>
    </p>
</h:form>
<!-- Show all categories -->
<div>
    <ul jsf:id="categories">
        <c:forEach items="${noteBackBean.categories}" var="category">
            <li>${category}</li>
        </c:forEach>
    </ul>
</div>

You can see a new jsf tag <f:ajax> is added inside the <h:commandButton> tag, and this will enable ajax functionality. The ajax request is triggered when user clicks the button.

The render attribute specifies which part of the page will be refreshed after the ajax request has compeleted. The value could be the component id. Here, the render is the id of the <ul> list that shows all categories by using jstl <c:foreach> tag.

The execute attribute indicates when the ajax request has initiated, which component’s value should be send to the server, the value could be the component id too.

The onevent attribute is to invoke javascript methods during each phase of ajax request. You can use it to monitor the request and response data and do some business logic upon your requirements.

Add JavaScript library

To add CSS, JS, or image resources to a JSF project, you need to create a folder named resources under WebContent folder. Here I created a script.js file in the sub-folder of resources, named js:

You can use <h:outputScript> to include this file.

<h:outputScript target="head" library="js" name="script.js" />

The target attribute is set to head, which will generate the <script> tag inside the <head> tag.

The library attribute is the name of the sub-folder that your resource file located in.

The name attritute is your resource file name.

The content of the script.js file is:

function handleEvent(event) {
    console.log(event);
}

It has a function named handleEvent, which is used in the <f:ajax> tag described in the previous section. It simply, for debugging purpose, logs the value of the event paratmeter passed by JSF.

Back Bean Implementation

Let’s see how the noteBackBean.addCategory method is implemented. The code for the NoteBackBean class:

package com.zxuqian.notebook.web;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@ManagedBean
@RequestScoped
public class NoteBackBean {

    private String name;
    private String email;
    private String note;
    private String categoryName;

    private List<String> categories = new ArrayList<>();

    public static final String CATEGORY_SESSION_KEY = "category";

    //private static final Logger log = Logger.getLogger(Note.class.getCanonicalName());

    public void addCategory() {
        categories.add(categoryName);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }

    public List<String> getCategories() {
        FacesContext context = FacesContext.getCurrentInstance();
        Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
        if(sessionMap.get(CATEGORY_SESSION_KEY) == null) {
            sessionMap.put(CATEGORY_SESSION_KEY, categories);
        } else {
            categories = (List<String>)sessionMap.get(CATEGORY_SESSION_KEY);
        }
        return categories;
    }

    public void setCategories(List<String> categories) {
        this.categories = categories;
    }
}

The categories are stored in a List collection object. As we are now concentrated on JSF, we will try to use other Java EE features, such as JPA, EJB, as less as possible. The cateogry list will be store in the session map, using the value of the constant variable CATEGORY_SESSION_KEY as the key. Each time the getCategories method is getting called, it will check the session if there is aready a category list object in the map.

Run the application

After running the application, you can add categories without refreshing the page:

And you can also debug the javascript code to see the ajax request progress (notice the value of status):