i am using a selectMultiMenu from bootsFaces, the initial values are showed perfectly, but after rendered, with the new values the combo doesnt open, if I check the source code in my browser it shows that the bean loeaded the values correctly. It only happens with this bootsFaces's element, the rest of my project with jsf render with no problems with ajax.
Any clue? Thanks!
<h:form id="form-Principal">
<h:panelGroup id="panel-Principal" layout="block" >
<div class="col-md-12">
<div class="col-md-1">
<label for="servicio" class="control-label">Servicio:</label>
</div>
<div class="col-md-2">
<h:selectOneMenu disabled="#{empty testops.ambiente}" id="servicio" class="combobox form-control" value="#{testops.servicio}" >
<f:selectItem itemValue="" itemLabel="Seleccione..."/>
<f:selectItems value="#{testops.listServicios}" />
<f:ajax event="change" listener="#{testops.obtenerOperaciones}" render="cboperacion" execute="#this"></f:ajax>
</h:selectOneMenu>
<h:message for="servicio" class="error"/>
</div>
<div class="col-md-1">
<label for="operacion" class="control-label">Operación:</label>
</div>
<div class="col-md-2">
<b:selectMultiMenu id="cboperacion" value="#{testops.operacion}" nonSelectedText="Seleccione...">
<f:selectItems value="#{testops.operaciones}"/>
</b:selectMultiMenu>
</div>
<div class="col-md-1">
</div>
<div class="col-md-1">
<f:ajax render=":salida form-Principal:panel-Principal" execute="#form" onevent="loading">
<h:commandLink class="btn btn-danger boton_rojo pull-right" value="Ejecutar" action="#{testops.ejecutarOperaciones()}"></h:commandLink>
</f:ajax>
</div>
</div>
</h:panelGroup>
</h:form>enter code here
Onload:
After rendering, it has diffent values, but combo is not display.
I've tried to reproduce your bug without success. Or rather: the code works as intended. The <b:selectMultMenu> is updated with the new values.
[meta] I know this isn't an answer (yet)... I just chose the answer because it's the only way to include source code. [/meta]
So I suggest you
copy me example code below into your project and see if it works
or you send me a "reproducer", i.e. a tiny but complete project showing the problem. For instance, you could upload a Maven project to GitHub. Please reduce the reproduces as much as possible. For instance, I need to be able to run it without configuring a database.
Here's the sourcecode I used to reproduce your bug:
As a basis, I used our showcase.
I copied your JSF code snippet into the empty.xhtml.
I created a JSF bean as follows:
package de.beyondjava.jsf.sample.carshop;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class Testops {
private String ambiente = "que";
private List<String> listServicios = new ArrayList<>();
private String operacion;
private List<String> operaciones = new ArrayList<>();
private String servicio;
{
listServicios.add("Servicio 1");
listServicios.add("Servicio 2");
shuffleOperaciones();
}
public void ejecutarOperaciones(Object o) {
}
public String getAmbiente() {
return ambiente;
}
public List<String> getListServicios() {
return listServicios;
}
public String getOperacion() {
return operacion;
}
public List<String> getOperaciones() {
return operaciones;
}
public String getServicio() {
return servicio;
}
public void obtenerOperaciones(Object o) {
shuffleOperaciones();
}
public void setAmbiente(String ambiente) {
this.ambiente = ambiente;
}
public void setListServicios(List<String> listServicios) {
this.listServicios = listServicios;
}
public void setOperacion(String operacion) {
this.operacion = operacion;
}
public void setOperaciones(List<String> operaciones) {
this.operaciones = operaciones;
}
public void setServicio(String servicio) {
this.servicio = servicio;
}
private void shuffleOperaciones() {
operaciones = new ArrayList<>();
for (int i = 0; i < 4; i++) {
operaciones.add("opción " + Math.ceil(Math.random()*1000));
}
}
}
When I chose one of the options of the first combobox, the <b:selectMultiMenu> is updated with the new (random) values.
Related
I have a simple form in JSF and I want to add the bean associated with this form in an ArrayList.
Here my form :
<h:form styleClass="form-horizontal">
<div class="row bottom-offset-20">
<div class="col-sm-4">
<div>
<h:outputLabel for="pseudo">pseudo</h:outputLabel>
</div>
<div>
<h:inputText id="pseudo" styleClass="form-control input-lg" value="${storyController.story.author}"/>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h:commandButton action="#{storyController.save}" styleClass="btn btn-primary btn-lg" value="send.story.button"/>
</div>
</div>
</h:form>
My controller :
#Named
#RequestScoped
public class StoryController implements Serializable {
private DefaultStoryService defaultStoryService;
#Inject
private Story story;
#Inject
public StoryController(DefaultStoryService defaultStoryService) {
this.defaultStoryService = defaultStoryService;
}
public String save() {
defaultStoryService.save(story);
return "index.xhtml";
}
public void setStory(Story story) {
this.story = story;
}
public Story getStory() {
return story;
}
}
The service :
#Named
#RequestScoped
public class DefaultStoryService {
#Inject
StoryMock mock;
public void save(Story story) {
mock.addStory(story);
}
}
The ArrayList:
#Named
#SessionScoped
public class StoryMock implements Serializable {
private List<Story> stories;
#PostConstruct
public void setupData() {
stories = new ArrayList<>();
}
public List<Story> getStories() {
return stories;
}
public void setStories(List<Story> stories) {
this.stories = stories;
}
public void addStory(Story story) {
stories.add(story);
}
}
And the story bean:
#Model
public class Story implements Serializable {
private Long id;
private String author;
}
My problem is that when a create a new story and save it, all the stories in the list are updated with the new values.
In my debugger, at the first call :
first call
And the second call :
second call
It's like the request scope does not work.
I don't get why the bean is not just add to the list, but it replace all the bean added before.
Please create and assign the Story object in a postconstruct method in controller and do not use #Inject to inject it.
Basically , in the input.xhtml there is a form which takes a username and password and if they are equal to a specific value(doesn't matter the value) the program should print a message in the browser, but this doesn't happen. To make sure of the problem i added 2 lines of "System.out.println(...)" where i print the value of the property and what i found out is that the properties are still null even after i submit. So after i click send in the console is written "null null". Any help is appreciated!
This is the UserBean class (backing bean)
package bean;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class UserBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private String password;
private String output_message;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String go(){
output_message = "";
if(name == null && password == null){
output_message += "Both fields cannot be empty!";
}else if(name == "name" && password == "pass"){
output_message += "Success!";
}else{
output_message += "Data is wrong!";
}
System.out.println(name);
System.out.println(password);
return output_message;
}
public String getOutput_message() {
return output_message;
}
public void setOutput_message(String output_message) {
this.output_message = output_message;
}
public String ret(String r){
return r;
}
}
This is the input.xhtml file, that contains the form that will submit the data to the bean. (Ignore the url to template.xhtml, it's just a parent template that has a header and a footer other than the mid-content that input.xhtml defines)
<!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://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:cc="http://java.sun.com/jsf/composite/myComponent">
<ui:composition template="/WEB-INF/templates/template.xhtml">
<ui:define name="content">
<style type="text/css">
#form1{
position: absolute;
top: 20%;
left:40%;
border: 1px solid black;
background-color: orange;
}
td{
padding-top:10px;
}
input[type="text"]{
backgorund-color:blue;
}
</style>
<form id="form1" method="post">
<table columns="2">
<tr>
<td><span>Emri:</span></td>
<td><input type="text" id="emri" value="#{userBean.name}"/></td>
</tr>
<tr>
<td><span>Password:</span></td>
<td><input type="password" id="pass" value="#{userBean.password}"/></td>
</tr>
<tr>
<td colspan="2" align="center"><button type="submit" onclick="#{userBean.go()}">Send</button></td>
</tr>
</table>
</form>
<p>#{user.output_message}</p>
</ui:define>
</ui:composition>
</html>
The problem caused by the button html tag. Don't use HTML buttons or anchors if you want to use the JSF mechanism. Instead use (button/link) components to submit the page. Define the navigation rules ot the userBean.go should pass back the next page name.
I just solved this. the problem was with the input tag, the value attribute does not represent the value written in the textbox is just some kind of a default value or somekind of a pre-value. Anyway instead of input and form tags i used and which worked out fine
h is a namespace with url xmlns:h="http://xmlns.jcp.org/jsf/html"
Here is my code of my .xhtml page
<ui:composition 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"
template="/WEB-INF/templates/admin/main_body_template.xhtml">
<ui:define name="bodycontent">
<h:panelGroup>
<h:form class="form-horizontal" enctype="multipart/form-data">
<!-- Build page from here: Usual with <div class="row-fluid"></div> -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default" style="min-height: inherit;">
<div class="panel-heading">
<h4><span class="icon16 icomoon-icon-pencil-3"></span><span>Create New Module</span></h4>
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-lg-5 control-label" for="select">Select app</label>
<div class="col-lg-3 dropdown-error">
<h:selectOneMenu class="form-control" required="required" value="#{moduleBean.appList}">
<f:selectItem itemValue="0" itemLabel="-- Please select app --"></f:selectItem>
<f:selectItem itemValue="1" itemLabel="AdMan"></f:selectItem>
<f:selectItem itemValue="2" itemLabel="Neokala"></f:selectItem>
<f:selectItem itemValue="3" itemLabel="Recrudesk"></f:selectItem>
<f:selectItem itemValue="4" itemLabel="E-commerce"></f:selectItem>
<f:selectItem itemValue="5" itemLabel="Restaurants"></f:selectItem>
<f:selectItem itemValue="6" itemLabel="Account"></f:selectItem>
<f:selectItem itemValue="7" itemLabel="MockExam"></f:selectItem>
</h:selectOneMenu>
</div>
</div>
<!-- End .form-group -->
<hr/>
<div class="form-group a1">
<label class="col-lg-5 control-label" for="normalInput">Module name</label>
<div class="col-lg-3">
<h:inputText class="form-control" required="true" value="#{moduleBean.selected.moduleName}"></h:inputText>
</div>
<a href="#"
class="btip"
rel="tooltip"
data-placement="right"
data-original-title="Tooltip on right">
<span class="icon16 entypo-icon-help-2 icon-position"></span>
</a>
</div>
<!-- End .form-group -->
<div class="form-group b1">
<label class="col-lg-5 control-label" for="fileinput">Upload image</label>
<div class="col-lg-3">
<h:inputFile class="form-control" id="file" value="#{moduleBean.imgFile}"/>
</div>
<a href="#"
class="btip"
rel="tooltip"
data-placement="right"
data-original-title="Tooltip on right">
<span class="icon16 entypo-icon-help-2 icon-position"></span>
</a>
</div>
<!-- End .form-group -->
<div class="form-group">
<label class="col-lg-5 control-label" for="checkboxes">Active</label>
<div class="col-lg-3">
<div class="normal-toggle-button toggle-custom-size">
<h:selectBooleanCheckbox class="nostyle" value="#{moduleBean.selected.active}"></h:selectBooleanCheckbox>
</div>
</div>
</div>
<!-- End .form-group -->
<div class="form-group">
<label class="col-lg-5 control-label" for="checkboxes">Add-on</label>
<div class="col-lg-3">
<div class="left marginR10">
<div class="normal-toggle-button toggle-custom-size">
<h:selectBooleanCheckbox class="nostyle" value="#{moduleBean.selected.addOn}"></h:selectBooleanCheckbox>
</div>
</div>
</div>
</div>
<!-- End .form-group -->
</div>
<div class="panel-heading form-footer-top">
<div class="footer-btn-position">
<h:commandButton class="btn btn-primary nostyle marginR5" value="Save" action="#{moduleBean.create()}"></h:commandButton>
<h:commandButton type="button" class="btn btn-warning nostyle cancel-btn-position" value="Cancel"></h:commandButton>
</div>
<div style="clear:both;"></div>
</div>
</div>
<!-- End .panel -->
</div>
<!-- End .span12 -->
</div>
<!-- End .row -->
</h:form>
</h:panelGroup>
</ui:define>
</ui:composition>
and below is my managedbean code.
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.aptegrainc.ymapps.supadm.managedbeans.masters;
import com.aptegrainc.ymapps.supadm.controller.masters.ModuleController;
import com.aptegrainc.ymapps.supadm.dto.ModuleVo;
import com.aptegrainc.ymapps.supadm.managedbeans.UserDataBean;
import static com.aptegrainc.ymapps.supadm.managedbeans.UserDataBean.setErrorMessage;
import static com.aptegrainc.ymapps.supadm.managedbeans.UserDataBean.setInfoMessage;
import java.io.Serializable;
import java.util.List;
import java.util.ResourceBundle;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.servlet.http.Part;
/**
*
* #author Vaibhavi
*/
#ManagedBean(name = "moduleBean")
#ViewScoped
public class ModuleBean extends UserDataBean implements Serializable{
private static final long serialVersionUID = 1L;
private DataModel items;
private ModuleVo current;
private Part imgFile;
private boolean createPanel = false;
private ModuleController moduleController = new ModuleController();
private String appList;
public Part getImgFile() {
return imgFile;
}
public void setImgFile(Part imgFile) {
this.imgFile = imgFile;
}
public ModuleVo getSelected() {
if (current == null) {
current = new ModuleVo();
}
return current;
}
/**
* Creates a new instance of ModuleBean
*/
public ModuleBean() {
}
public String create() {
System.out.println("current : " + current);
System.out.println("---------"+current.getAppName()+current.getModuleName()+current.isActive()+current.isAddOn());
if(checkError()){
try {
System.out.println("---------"+current.getAppName()+current.getModuleName()+current.isActive()+current.isAddOn());
current.setActive(true);
boolean val = moduleController.create(current);
if(!val){
return "pretty:commonerror";
} else if (val){
setInfoMessage("Module created successfully");
}
setCreatePanel(false);
recreateModel();
return "success";
} catch (Exception e) {
setErrorMessage(ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
}
}
return "fail";
}
public boolean checkError(){
boolean flag = true;
if(current.getModuleName() == null || current.getModuleName().equals("")){
//setErrorMessage("Enter module name");
flag = false;
}
return flag;
}
private void recreateModel() {
items = null;
}
// Getters, Setters
/**
* #return the items
*/
public DataModel getItems() {
if (items == null) {
List<ModuleVo> moduleVos = null;
//moduleVos = moduleController.findAll();
items = new ListDataModel(moduleVos);
}
return items;
}
/**
* #param items the items to set
*/
public void setItems(DataModel items) {
this.items = items;
}
/**
* #return the current
*/
public ModuleVo getCurrent() {
return current;
}
/**
* #param current the current to set
*/
public void setCurrent(ModuleVo current) {
this.current = current;
}
/**
* #return the moduleController
*/
public ModuleController getModuleController() {
return moduleController;
}
/**
* #param moduleController the moduleController to set
*/
public void setModuleController(ModuleController moduleController) {
this.moduleController = moduleController;
}
/**
* #return the appList
*/
public String getAppList() {
return appList;
}
/**
* #param appList the appList to set
*/
public void setAppList(String appList) {
this.appList = appList;
}
/**
* #return the createPanel
*/
public boolean isCreatePanel() {
return createPanel;
}
/**
* #param createPanel the createPanel to set
*/
public void setCreatePanel(boolean createPanel) {
this.createPanel = createPanel;
}
}
I have just called a method on submit button but its not calling even the method. I have checked the code many times but couldn't find any logical error. I am not getting why the bean method is not called.
I've got a bit of a problem. Basically I have a page with a form containing an input text field, a search button and a ui:repeat structure that displays the results of the search using more input text fields and a couple of other buttons (the idea is to list all search hits and allow the user to edit them directly from the same page). Now, the search and the display part works well - it does what it's supposed to. However, when I try to click on one of the buttons that are displayed in the ui:repeat section, the action isn't invoked.
When I press the search button (Pretraga in code) a function is called in the Kupac bean which then gets the results from the database and places them into a list and finally redirects back to the same page (from my understanding this will load the page again) and lists the results using the ui:repeat component. But as I said, when I press the other buttons (Izmeni and Glavna in code) they do nothing. Kupac bean is #RequestScoped and I already tried changing it to #ViewScoped, however this only made it worse by having the search not work as well (i.e. it will display nothing).
Here's the JSF page code:
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Pregled kupaca</title>
</h:head>
<h:body>
<h3 align="center">Pregled kupaca</h3>
<h:form>
<table align="center">
<tr>
<td align="center" colspan="2"><h:link outcome="pocetna.xhtml">Pocetna</h:link></td>
</tr>
<tr>
<td>Firma</td>
<td><h:inputText value="#{kupac.naziv_firme}"/></td>
</tr>
<tr>
<td align="center" colspan="2">
<h:commandButton action="#{kupac.listKupci()}" value="Pretraga">
</h:commandButton>
</td>
</tr>
</table>
<br/>
<ui:repeat value="#{kupac.zeljeni_kupci}" var="kupac">
<table align="center" border="1">
<tr>
<td>Ime i prezime</td>
<td><h:inputText
required="true"
requiredMessage="Niste uneli ime i prezime!"
value="#{kupac.ime_prezime}"/></td>
</tr>
<tr>
<td>Adresa</td>
<td><h:inputText
required="true"
requiredMessage="Niste uneli adresu!"
value="#{kupac.adresa}"/></td>
</tr>
<tr>
<td>Naziv firme</td>
<td><h:inputText
required="true"
requiredMessage="Niste uneli naziv firme!"
value="#{kupac.naziv_firme}"/></td>
</tr>
<tr>
<td>Adresa firme</td>
<td><h:inputText
required="true"
requiredMessage="Niste uneli adresu firme!"
value="#{kupac.adresa_firme}"/></td>
</tr>
<tr>
<td>Br. telefona</td>
<td><h:inputText
required="true"
requiredMessage="Niste uneli broj telefona!"
value="#{kupac.br_tel}"/></td>
</tr>
<tr>
<td>
<h:commandButton value="Izmeni" action="#{kupac.izmenaKupca()}"/>
</td>
<td><h:commandButton action="#{kupac.test()}" value="Glavna"/></td>
</tr>
</table>
<br/><br/>
</ui:repeat>
</h:form>
</h:body>
</html>
and here's the full bean code in Java:
package beans;
import exceptions.DBException;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.ViewScoped;
import util.Database;
#ManagedBean
#RequestScoped
public class Kupac implements Serializable {
private int id_kupac;
private String ime_prezime;
private String adresa;
private String naziv_firme;
private String adresa_firme;
private String br_tel;
private List<Kupac> svi_kupci;
private List<Kupac> zeljeni_kupci;
public void init() {
listKupci();
}
public void poruka() {
System.out.println("ID "+id_kupac);
}
public String test() {
return "pocetna";
}
public String izmenaKupca() throws DBException {
Kupac kupac = new Kupac();
Database db = Database.getInstance();
kupac.setId_kupac(id_kupac);
kupac.setIme_prezime(ime_prezime);
kupac.setAdresa(adresa);
kupac.setNaziv_firme(naziv_firme);
kupac.setAdresa_firme(adresa_firme);
kupac.setBr_tel(br_tel);
try {
db.updateKupac(kupac);
} catch (DBException ex) {
return "error";
}
return "pregled_kupaca";
}
public String unosKupca() throws DBException {
Kupac kupac = new Kupac();
Database db = Database.getInstance();
kupac.setIme_prezime(ime_prezime);
kupac.setAdresa(adresa);
kupac.setNaziv_firme(naziv_firme);
kupac.setAdresa_firme(adresa_firme);
kupac.setBr_tel(br_tel);
try {
db.insertKupac(kupac);
} catch (DBException ex) {
return "error";
}
return "pocetna";
}
public String listKupci() {
Database db = Database.getInstance();
zeljeni_kupci = new LinkedList<Kupac>();
try {
svi_kupci = db.listKupci();
for (Kupac k : svi_kupci) {
if (k.naziv_firme.equals(naziv_firme) || "".equals(naziv_firme)) {
zeljeni_kupci.add(k);
}
}
} catch (DBException ex) {
return "error";
}
return "pregled_kupaca";
}
public List<Kupac> getZeljeni_kupci() {
return zeljeni_kupci;
}
public void setZeljeni_kupci(List<Kupac> zeljeni_kupci) {
this.zeljeni_kupci = zeljeni_kupci;
}
public List<Kupac> getSvi_kupci() {
return svi_kupci;
}
public void setSvi_kupci(List<Kupac> svi_kupci) {
this.svi_kupci = svi_kupci;
}
public int getId_kupac() {
return id_kupac;
}
public void setId_kupac(int id_kupac) {
this.id_kupac = id_kupac;
}
public String getIme_prezime() {
return ime_prezime;
}
public void setIme_prezime(String ime_prezime) {
this.ime_prezime = ime_prezime;
}
public String getAdresa() {
return adresa;
}
public void setAdresa(String adresa) {
this.adresa = adresa;
}
public String getNaziv_firme() {
return naziv_firme;
}
public void setNaziv_firme(String naziv_firme) {
this.naziv_firme = naziv_firme;
}
public String getAdresa_firme() {
return adresa_firme;
}
public void setAdresa_firme(String adresa_firme) {
this.adresa_firme = adresa_firme;
}
public String getBr_tel() {
return br_tel;
}
public void setBr_tel(String br_tel) {
this.br_tel = br_tel;
}
/**
* Creates a new instance of Kupac
*/
public Kupac() {
}
}
I'm using JSF 2.2 on a GlassFish 4.0 server using Netbeans 7 IDE.
Sorry for the long post and the fact that this question has now been asked several times, but I haven't managed to fix it for 2 hrs now and would appreciate any help. Cheers!
I'm using RichFaces component library and I want to manage the history of Ajax navigation, so the enduser can use the browser back and forward buttons.
Is there any clean way to do it, design pattern, library, etc?
You can use RSH to handle Ajax history
For the example lets assume that you have a page where the user should select a color.
Then, the selected color is posted to the server using XmlHttpRequest.
Now we want to restore previous selection when the back and forward navigation buttons is pressed.
Code Example
Bean:
public class Bean {
private static final String DAFAULT_COLOR = "green";
private Map<String, Color> colors;
private Color selectedColor;
private String restoredColor;
#PostConstruct
public void init() {
this.colors = new HashMap<String, Color>();
this.colors.put("green", new Color("Green", "008000"));
this.colors.put("blue", new Color("Blue", "0000FF"));
this.colors.put("red", new Color("Red", "FF0000"));
this.colors.put("purple", new Color("Purple", "FF0000"));
this.colors.put("purple", new Color("Purple", "800080"));
this.colors.put("yellow", new Color("Yellow", "FFFF00"));
this.colors.put("silver", new Color("Silver", "C0C0C0"));
this.colors.put("black", new Color("Black", "000000"));
this.colors.put("white", new Color("White", "FFFFFF"));
this.selectedColor = this.colors.get(DAFAULT_COLOR);
}
public void setSelectedColor(ActionEvent event) {
UIComponent component = event.getComponent();
String color = ((String)component.getAttributes().get("color")).toLowerCase();
this.selectedColor = this.colors.get(color);
}
public void restoreColor() {
if(restoredColor.equals("") || restoredColor.equals("null")) {
restoredColor = DAFAULT_COLOR;
}
this.selectedColor = this.colors.get(restoredColor);
}
public List<Color> getColors() {
return Arrays.asList(colors.values().toArray(new Color[0]));
}
public Color getSelectedColor() {
return selectedColor;
}
public String getRestoredColor() {
return restoredColor;
}
public void setRestoredColor(String restoredColor) {
this.restoredColor = restoredColor.toLowerCase();
}
}
View:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:t="http://myfaces.apache.org/tomahawk"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
template="/WEB-INF/template/default.xhtml">
<ui:define name="head">
<script type="text/javascript" src="#{request.contextPath}/js/rsh/rsh.js"></script>
<script type="text/javascript">
window.dhtmlHistory.create({
toJSON: function(o) {
return Object.toJSON(o);
},
fromJSON: function(s) {
return s.evalJSON();
}
});
Event.observe(window, 'load', function() {
dhtmlHistory.initialize();
dhtmlHistory.addListener(handleHistoryChange);
});
var registerHistoryPoint = function(newLocation, historyData) {
dhtmlHistory.add(newLocation, historyData);
};
</script>
</ui:define>
<ui:define name="content">
<a4j:form id="frmColor">
<div class="colors">
<ul>
<a4j:repeat value="#{bean.colors}" var="color">
<li style="background:##{color.hex};">
<a4j:commandLink value=" "
actionListener="#{bean.setSelectedColor}"
reRender="frmColor"
oncomplete="registerHistoryPoint('#{color.name}', '#{color.name}');">
<f:attribute name="color" value="#{color.name}"/>
</a4j:commandLink>
</li>
</a4j:repeat>
</ul>
</div>
<div class="selection" style="background:##{bean.selectedColor.hex};">
<div class="selected-color"
style="color: ##{bean.selectedColor.name eq 'White' or
bean.selectedColor.name eq 'Yellow' ? '000000' : 'ffffff'}">
<h:outputText value="#{bean.selectedColor.name}"/>
</div>
</div>
<a4j:jsFunction name="handleHistoryChange" reRender="frmColor"
action="#{bean.restoreColor}">
<a4j:actionparam name="historyData" assignTo="#{bean.restoredColor}" />
</a4j:jsFunction>
</a4j:form>
</ui:define>
</ui:composition>
Now when the user click on a color the registerHistoryPoint is invoked. This will register historyData that will be passed to the bean when the back and forward buttons is pressed.
e.g.
User select Yellow.
Yellow is registered.
User select Blue.
Blue is registered.
User click on back.
Yellow is restored.
User click forward.
Blue is restored.