Enterprise Java

JSF Simple Ajax Samples

Today we will see some Simple Samples of Ajax with JSF.

If you want to see other posts about JSF/Web Applications click on the next links: JSF Persisting Objects and Messages after a Redirect ,User Login Validation with JAAS and JSF, JSF: Converter and Bean AutoComplete, JSF – Hello World, Auto Complete, Handling Exceptions on a WebApp, User Authentication (Filter/Servlet), Creating a WebServer.

In the end of this post you will find the link to download the source code of the samples. In this post (User Login Validation with JAAS and JSF) I show how to install the JBoss 6 in case you want to run the project from today. You will need to install the JBoss tools plugin in your Eclipse.

Take a look at the page bellow and its code:

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:ui='http://java.sun.com/jsf/facelets' xmlns:h='http://java.sun.com/jsf/html'
 xmlns:f='http://java.sun.com/jsf/core'>
<h:head>
</h:head>
<h:body>
 <h:form>
  Your Name: <h:inputText id='inputname' label='${msgs.prompt}' value='#{user.name}'/>
  <br />
  <h:commandButton action='#{user.sayHello}' value='Display my name here, now!'/>
  <br />
 </h:form>
</h:body>
</html>

How could we display the typed name in the same screen using Ajax? Piece of cake, just add the “f:ajax” component. Check the code update and the result:

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:ui='http://java.sun.com/jsf/facelets' xmlns:h='http://java.sun.com/jsf/html'
 xmlns:f='http://java.sun.com/jsf/core'>
<h:head>
</h:head>
<h:body>
 <h:form>
  Your Name: <h:inputText id='inputname' label='${msgs.prompt}' value='#{user.name}'/>
  <br />
  <h:commandButton action='#{user.sayHello}' value='Display my name here, now!'>
   <f:ajax render='myName' execute='inputname' />
  </h:commandButton>
  <br />
  <br />
  <h:outputText id='myName' value='#{user.name}' />
 </h:form>
</h:body>
</html>

It is very easy right? We just need to pass the value that will be carried to the ManagedBean by the “execute” parameter; with the “render” parameter we will tell to the JSF which component will be “refreshed”.

Notice also that the typed name appears in the Console.

With this code we can “refresh” all kind of components. Let us see another sample?

Let us display an error message if the user types a name with less than 4 characters.

Check our new message and the new code:

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:ui='http://java.sun.com/jsf/facelets' xmlns:h='http://java.sun.com/jsf/html'
 xmlns:f='http://java.sun.com/jsf/core'>
<h:head>
</h:head>
<h:body>
 <h:form>
  <h:messages id='myMessage' globalOnly='true' showDetail='true'/>
  Your Name: <h:inputText id='inputname' label='${msgs.prompt}' value='#{user.name}'/>
  <br />
  <h:commandButton action='#{user.sayHello}' value='Display my name here, now!'>
   <f:ajax render='myName myMessage' execute='inputname' />
  </h:commandButton>
  <br />
  <br />
  <h:outputText id='myName' value='#{user.name}' />
 </h:form>
</h:body>
</html>
package demo;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = 'user')
@RequestScoped
public class User {

 private String name;

 public String sayHello() {
  if (isNameIncorrect()) {
   FacesContext context = FacesContext.getCurrentInstance();
   context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, 'Too small', 'Can you write it a little bigger?'));
  }

  System.out.println(name);
  return null;
 }

 private boolean isNameIncorrect() {
  return ''.equals(name.trim()) || name.length() < 3;
 }

 public String getName() {
  return name;
 }

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

Notice that we have the component “h:messages” and its ID is used in the “f:ajax” component. This code also works when you use the “h:message for=“YYY”” component.

What if we work now with comboboxes? Let us display a combobox that will contain 4 items when we have a name with less than 6 characters, and a list with more than 4 items if the typed name has more than 6 characters.

package demo;

import java.util.ArrayList;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UISelectItems;
import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = 'user')
@RequestScoped
public class User {

 private String name;

 private List<String> cars;

 private String selectedCar;
 private HtmlSelectOneMenu htmlSelectCars;

 private static final String SELECT_A_CAR = 'Select One Car';

 public User() {
  cars = new ArrayList<String>();
 }

 public String sayHello() {
  if (isNameInCorrect()) {
   FacesContext context = FacesContext.getCurrentInstance();
   context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, 'Too small', 'Can you write it a little bigger?'));
  }

  System.out.println(name);
  return null;
 }

 private boolean isNameInCorrect() {
  return name == null || ''.equals(name.trim()) || name.length() < 3;
 }

 public String getName() {
  return name;
 }

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

 public void editMyCarsList(AjaxBehaviorEvent event) {
  if (htmlSelectCars == null) {
   htmlSelectCars = new HtmlSelectOneMenu();
  }

  htmlSelectCars.getChildren().clear();

  UISelectItems items = new UISelectItems();
  items.setValue(getCars());
  htmlSelectCars.getChildren().add(items);
 }

 public List<String> getCars() {
  cars.clear();

  cars.add(SELECT_A_CAR);

  if (!isNameInCorrect() && name.length() >= 6) {
   cars.add('Ferrari');
   cars.add('Porch');
   cars.add('Beetle');
   cars.add('Opala');
   cars.add('Passat');
   cars.add('Vectra');
   cars.add('Chevet');
   cars.add('Corvet');
  } else {
   cars.add('Ferrari');
   cars.add('Porch');
   cars.add('Beetle');
   cars.add('Opala');
  }

  return cars;
 }

 public void setCars(List<String> cars) {
  this.cars = cars;
 }

 public String getSelectedCar() {
  return selectedCar;
 }

 public void setSelectedCar(String selectedCar) {
  this.selectedCar = selectedCar;
 }

 public HtmlSelectOneMenu getHtmlSelectCars() {
  editMyCarsList(null);

  return htmlSelectCars;
 }

 public void setHtmlSelectCars(HtmlSelectOneMenu htmlSelectCars) {
  this.htmlSelectCars = htmlSelectCars;
 }
}

Take a look now at our page:

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:ui='http://java.sun.com/jsf/facelets' xmlns:h='http://java.sun.com/jsf/html'
 xmlns:f='http://java.sun.com/jsf/core'>
<h:head>
</h:head>
<h:body>
 <h:form>
  <h:messages id='myMessage' globalOnly='true' showDetail='true' />
  Your Name: <h:inputText id='inputname' label='${msgs.prompt}' value='#{user.name}' />
  <br />
  <h:commandButton action='#{user.sayHello}' value='Display my name here, now!'>
   <f:ajax render='myName myCars myMessage' execute='inputname' listener='#{user.editMyCarsList}' />
  </h:commandButton>
  <br />
  <br />
  <h:outputText id='myName' value='#{user.name}' />
  <br />
  <br />
  Choose your car: <h:selectOneMenu id='myCars' binding='#{user.htmlSelectCars}' value='#{user.selectedCar}' />
  <br />
  <br />
 </h:form>
</h:body>
</html>

Notice that our combobox items size is updated according to the typed name. At the end of this post I will talk more about why I used the binding attribute to the HtmlSelectOneMenu instead returning the List<String>.

As our last sample, let us create a combobox that will appear and disappear according to the selected value in the Car combobox.

Take a look at our ManagedBean:

package demo;

import java.util.ArrayList;
import java.util.List;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.UISelectItems;
import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;

/**
 * Created by JBoss Tools
 */
@ManagedBean(name = 'user')
@RequestScoped
public class User {

 private String name;

 private List<String> cars;
 private List<String> colors;

 private String selectedCar;
 private String selectedColor;
 private HtmlSelectOneMenu htmlSelectCars;

 private static final String SELECT_A_CAR = 'Select One Car';

 public User() {
  cars = new ArrayList<String>();
  colors = new ArrayList<String>();

  colors.add('Red');
  colors.add('Blue');
  colors.add('Orange');
  colors.add('Pink --> O.o');
 }

 public String sayHello() {
  if (isNameInCorrect()) {
   FacesContext context = FacesContext.getCurrentInstance();
   context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, 'Too small', 'Can you write it a little bigger?'));
  }

  System.out.println(name);
  return null;
 }

 private boolean isNameInCorrect() {
  return name == null || ''.equals(name.trim()) || name.length() < 3;
 }

 public String getName() {
  return name;
 }

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

 public void editMyCarsList(AjaxBehaviorEvent event) {
  if (htmlSelectCars == null) {
   htmlSelectCars = new HtmlSelectOneMenu();
  }

  htmlSelectCars.getChildren().clear();

  UISelectItems items = new UISelectItems();
  items.setValue(getCars());
  htmlSelectCars.getChildren().add(items);
 }

 public List<String> getCars() {
  cars.clear();

  cars.add(SELECT_A_CAR);

  if (!isNameInCorrect() && name.length() >= 6) {
   cars.add('Ferrari');
   cars.add('Porch');
   cars.add('Beetle');
   cars.add('Opala');
   cars.add('Passat');
   cars.add('Vectra');
   cars.add('Chevet');
   cars.add('Corvet');
  } else {
   cars.add('Ferrari');
   cars.add('Porch');
   cars.add('Beetle');
   cars.add('Opala');
  }

  return cars;
 }

 public void setCars(List<String> cars) {
  this.cars = cars;
 }

 public String getSelectedCar() {
  return selectedCar;
 }

 public void setSelectedCar(String selectedCar) {
  this.selectedCar = selectedCar;
 }

 public List<String> getColors() {
  return colors;
 }

 public void setColors(List<String> colors) {
  this.colors = colors;
 }

 public boolean isColorsAlloweToDisplay() {
  if (isNameInCorrect()) {
   return false;
  }

  if (selectedCar == null || selectedCar.trim().equals('') || selectedCar.equals(SELECT_A_CAR)) {
   return false;
  }

  return true;
 }

 public String getSelectedColor() {
  return selectedColor;
 }

 public void setSelectedColor(String selectedColor) {
  this.selectedColor = selectedColor;
 }

 public HtmlSelectOneMenu getHtmlSelectCars() {
  editMyCarsList(null);

  return htmlSelectCars;
 }

 public void setHtmlSelectCars(HtmlSelectOneMenu htmlSelectCars) {
  this.htmlSelectCars = htmlSelectCars;
 }
}

Our ManagedBean were lightly updated, we just added a List with a method that return a list of colors that will populate our combobox; we added also a method that will return a Boolean – true if the combobox is allowed to be displayed.

Check our new page:

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:ui='http://java.sun.com/jsf/facelets' xmlns:h='http://java.sun.com/jsf/html'
 xmlns:f='http://java.sun.com/jsf/core'>
<h:head>
</h:head>
<h:body>
 <h:form>
  <h:messages id='myMessage' globalOnly='true' showDetail='true' />
  Your Name: <h:inputText id='inputname' label='${msgs.prompt}' value='#{user.name}' />
  <br />
  <h:commandButton action='#{user.sayHello}' value='Display my name here, now!'>
   <f:ajax render='myName myCars myMessage myColors' execute='inputname' listener='#{user.editMyCarsList}' />
  </h:commandButton>
  <br />
  <br />
  <h:outputText id='myName' value='#{user.name}' />
  <br />
  <br />
  Choose your car:
  <h:selectOneMenu id='myCars' binding='#{user.htmlSelectCars}' value='#{user.selectedCar}'>
   <f:ajax render='myColors' execute='inputname myCars'/>
  </h:selectOneMenu>
  <br />
  <br />
  <h:panelGroup id='myColors'>
   <h:selectOneMenu value='#{user.selectedColor}' rendered='#{user.colorsAlloweToDisplay}'>
    <f:selectItems value='#{user.colors}' />
   </h:selectOneMenu>
  </h:panelGroup>
 </h:form>
 </h:body>
</html>

I will talk about the code used in the post:

  • HtmlSelectOneMenu – I used the component instead a List because the JSF is not so good in render the components in the user screen (DOM Tree). If your combobox has 4 lines and by using ajax you add more lines to the List, the JSF/Ajax will not recognize the new added lines; you will be able to use only the older values. You can try to use the code with a List<String> instead using the HtmlSelectOneMenu and see the result; I spend like 3~4 hours to understand this by a lot of searches on the internet.
  • HtmlSelectOneMenu inside the “h:panelGroup” component – I did this because every time you want to render a non rendered component you need to update its container. If our selectOne were inside the same form of the car selectOne you would need to render all form.

Click here to download the code from this post.

I hope this post might help you.

If you have any question/doubt/suggestion just post it.

Reference: JSF Simple Ajax Samples from our JCG partner Hebert Coelho at the uaiHebert blog.

Hebert Coelho

Senior Java Development, with 4 certifications and a published book about JSF (portuguese only). Founder of the blog uaiHebert.com visited from more than 170 different countries.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button