Olá, tudo bem?
Hoje vamos exibir alguns simples modos de fazer chamadas Ajax utilizando JSF 2.0.
Para ver outros posts sobre Web Applications/JSF basta acessar os links a seguir: JSF Exibindo Objeto e Mensagens após Redirect, Validação de Login de Usuário com JSF e JAAS, JSF: Converter and Bean AutoComplete, JSF – Hello World, AutoComplete, Tratando Exceções em uma Aplicação Web, Autenticação de Usuários (Filter/Servlet), Criando um WebServer.
Ao final do post de hoje você verá o código para download. No post (Validação de Login de Usuário com JSF e JAAS) é exibido como instalar o JBoss 6 caso você queira executar o código do post de hoje. Você precisará instalar o JBoss Tools em seu Eclipse.
Veja a tela abaixo e seu respectivo código.

<!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>
Como exibir o nome digitado na mesma tela utilizando Ajax? Fácil, basta adicionar o comando “f:ajax” na linha e pronto. Veja a alteração e o resultado na página:

<!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>
Viu como é simples? Passei apenas o valor que será levado, para o ManagedBean, através do parâmetro “execute” e quem eu gostaria que o JSF atualizasse através do parâmetro “render”.
Repare que o nome digitado aparece no console também.
Esse exemplo serve para atualizar todos os tipos de componentes. Vamos para mais um?
Vamos fazer com que uma mensagem de erro seja exibida caso o nome preenchido tenha menos que 4 letras.
Veja o novo código da página e a mensagem exibida:

<!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;
}
}
Note no código que foi colocado um “h:messages” e ele tem seu ID utilizado pelo componente “f:ajax”. Essa solução também funciona quando você tem um componente do tipo “h:message for=”YYY””.
Vamos trabalhar agora com comboboxes? Iremos exibir um combobox que contenha no máximo 4 itens quando temos um nome com menos de 6 caracteres ou uma lista com mais de 4 itens quando temos um nome com mais de 6 caracteres:
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;
}
}
Repare agora nosso código na página:


<!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>
Como você pode perceber no código acima, o combobox tem seu valor alterado de acordo com o nome digitado. Ao final do post, irei explicar por que utilizei o binding ao componente HtmlSelectOneMenu ao invés de passar uma lista (List<String>) diretamente.
Como último exemplo, vamos fazer com que tenha um combobox invisível que só apareça quando o usuário tiver selecionado algum carro.
Veja como ficar nosso 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;
}
}
Repare que foram alterações bem simples, onde adicionamos um List um método que irá dizer quando a lista deve ser exibida ou não.
Veja como ficou nossa página:


<!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>
Agora farei diversas observações sobre o código e práticas adotadas:
- HtmlSelectOneMenu – Eu utilizei o componente ao invés de uma simples lista por um pequeno detalhe. O JSF ainda não se dá bem na hora de construir os objetos na tela (DOM Tree). Com isso, se a primeira lista tinha 4 itens e depois, via ajax, você adiciona mais itens ele não irá reconhecer os itens mais novos. Com isso mesmo com uma lista contendo um novo valor o JSF não irá reconhecer, e você irá apenas poder utilizar os valores antigos. Você pode tentar com List<String> ao invés do component HtmlSelectOneMenu apenas e ver o que vai acontecer, fiquei umas 3~4 horas de pesquisa para achar uma solução.
- HtmlSelectOneMenu dentro do “h:panelGroup” – Adicionei o selectOne dentro do panelGroup pois toda vez que um objeto não é exibido e você deseja exibi-lo é necessário atualizar todo seu container. Ou seja, se o segundo selectOne (cores) estivesse no mesmo “form”, você deveria utilizar seu “render” em todo o form.
Click Aqui para fazer o download do código do programa de hoje.
Espero que o post de hoje possa te ajuda.
Qualquer dúvida/pergunta/comentário poste abaixo.
Até a próxima