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.
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
):