How to freeze header of table in JSF - jsf

In my JSF 2.1 project, I am using a table where I have issues with header. If I use a single table for both header and data, the header is scrolling along with data.
If I use separate table for header and data i have alignment issues.
So is there any tag or any possible way to freeze header using single table for header and data?

There is a good answer to this for HTML: HTML table with fixed headers?. You just need to remember that JSF will generate plain HTML. Adapting the code from that answer, it comes with this solution (Note: You need to add the CDATA validation in order to use the "<" and ">" in JavaScript in Facelets):
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>Table Body Scroll Test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js">
</script>
<script>
/* <![CDATA[ */
function scrolify(tblAsJQueryObject, height) {
var oTbl = tblAsJQueryObject;
// for very large tables you can remove the four lines below
// and wrap the table with <div> in the mark-up and assign
// height and overflow property
var oTblDiv = $("<div/>");
oTblDiv.css('height', height);
oTblDiv.css('overflow','scroll');
oTbl.wrap(oTblDiv);
// save original width
oTbl.attr("data-item-original-width", oTbl.width());
oTbl.find('thead tr td').each(function() {
$(this).attr("data-item-original-width",$(this).width());
});
oTbl.find('tbody tr:eq(0) td').each(function() {
$(this).attr("data-item-original-width",$(this).width());
});
// clone the original table
var newTbl = oTbl.clone();
// remove table header from original table
oTbl.find('thead tr').remove();
// remove table body from new table
newTbl.find('tbody tr').remove();
oTbl.parent().parent().prepend(newTbl);
newTbl.wrap("<div/>");
// replace ORIGINAL COLUMN width
newTbl.width(newTbl.attr('data-item-original-width'));
newTbl.find('thead tr td').each(function() {
$(this).width($(this).attr("data-item-original-width"));
});
oTbl.width(oTbl.attr('data-item-original-width'));
oTbl.find('tbody tr:eq(0) td').each(function() {
$(this).width($(this).attr("data-item-original-width"));
});
}
$(document).ready(function() {
scrolify($('#tblNeedsScrolling'), 160); // 160 is height
});
/* ]]> */
</script>
</h:head>
<h:body>
<h:form id="myForm" prependId="false">
<div style="width:300px;border:6px green solid;">
<h:dataTable id="tblNeedsScrolling" value="#{tableScroll.data}" var="data" border="1" width="100%">
<h:column>
<f:facet name="header">
<h:outputText value="Data" />
</f:facet>
<h:outputText value="#{data}" />
</h:column>
</h:dataTable>
</div>
</h:form>
</h:body>
</html>
The managed bean for the example:
#ManagedBean
#RequestScoped
public class TableScroll {
private List<String> data;
public TableScroll() {
data = new ArrayList<String>();
for(int i = 1; i <= 20; i++) {
data.add("Name" + i);
}
}
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
}

Related

How can I avoid a partial http response flush of large JSF views?

Today I've spend several hours reproducing a very strange UI behavior in our web application using JSF facelets: In some cases the UI was partially rendered in the web browser before the server side really finished rendering the whole view.
In the end it all came down to an JSF view with a large number of elements – in my case items of a submenu. There seems to be some threshold that triggers a partial flush of the response.
Here is a minimized example that visually demonstrates that effect:
<?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 lang="de" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
<style>
td {
vertical-align: top;
}
</style>
</h:head>
<h:body>
<h1>EURNEU-10056</h1>
<table>
<tr>
<td>
<ol>
<ui:repeat value="#{bean.strings(10)}" var="str">
<li><h:outputText value="#{str}" /></li>
</ui:repeat>
</ol>
<h:outputText value="#{bean.delay(2000)}" />
</td>
<td>
<ol>
<ui:repeat value="#{bean.strings(10)}" var="str">
<li><h:outputText value="#{str}" /></li>
</ui:repeat>
</ol>
<h:outputText value="#{bean.delay(2000)}" />
</td>
<td><ol>
<ui:repeat value="#{bean.strings(10)}" var="str">
<li><h:outputText value="#{str}" /></li>
</ui:repeat>
</ol>
<h:outputText value="#{bean.delay(2000)}" />
</td>
</tr>
</table>
</h:body>
</html>
That simple view uses the following bean to generate a certain amount of strings and adds some artificial delays into the rendering of 2000ms after each of the 3 columns.
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.faces.bean.ManagedBean;
#ManagedBean
public class Bean implements Serializable {
private static final long serialVersionUID = 1L;
public List<String> strings(int count) {
List<String> all = new ArrayList<>();
for (int i = 0; i < count; i++) {
all.add(UUID.randomUUID().toString());
}
return all;
}
public String delay(int delay) {
try {
Thread.sleep(delay);
}
catch (InterruptedException ex) {
// NOP;
}
return String.format("This string has been delayed for %d ms!", delay);
}
}
The browsers shows the following phases while processing the request:
If I lower the amount of strings used while generating the view the response is only flushed at the very end of the render phase.
Is there anything I can do to avoid that partial rendering? (other than lowering the number of elements)
PS: We are using JBoss EAP v7.0.9 as a server. The application itself is quite complex.
It turned our that explizit defining of Facelets buffer-size in web.xml solves that problem.
<!-- We raise the buffer size to avoid partial rendering of complex pages. -->
<context-param>
<param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
<param-value>1024000</param-value>
</context-param>
That setting and the structure of the generated HTML define the very moment, the browser starts to render the response. In our case the menu was already renderable and showed much earlier than expected.

p:graphicImage and Fancybox Integration

I'm using JSF 2.2 with PrimeFaces 5.3 under the GlassFish 4.1
Inside the application I use the approach to show the images from the database.
So that means I don't have an URL.
There're tons of example from this point of view, but I will paste here in order to be more useful.
Here the facelets
<p:graphicImage value="#{applicationScopedBean.imagesFromDb}" class="img">
<f:param name="imageId" value="#{actualAd.favouriteImageId}" />
<f:param name="cvlTimeStamp" value="#{now}" />
</p:graphicImage>
And here the Backing Bean
public StreamedContent getImagesFromDb() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
} else {
// So, browser is requesting the image. Return a real StreamedContent with the image bytes.
String imageId = context.getExternalContext().getRequestParameterMap().get("imageId");
return new DefaultStreamedContent(new ByteArrayInputStream(imageManager.getById(Long.valueOf(imageId)).getContent()));
}
}
Here an example of a the generated HTML code
<img src="/myWebApp/faces/javax.faces.resource/dynamiccontent.properties?ln=primefaces&v=5.3&pfdrid=GgwXKejrBbRvnC%2Fxp98FzlaymhDf7Gb%2BEVoD%2BlqKVRmYUBBZeMmjKw%3D%3D&pfdrt=sc&imageId=23&myTimeStamp=Sun+May+15+19%3A19%3A08+CEST+2016&pfdrid_c=true">
By design, in order to use the gallery that comes from fancybox we need a code similar to the following
<a class="fancybox" rel="group" href="resources/bootstrap/css/images/single/1.jpg">
<img id="img_01" alt="" class="raised" src="resources/bootstrap/css/images/single/1.jpg" style="width: 100%" />
But using graphicImages with streams, I don't have the link needed in the href value.
There's a chance to retrieve the generated image url?
Basically I need to retrieve the generated string used to fill the src attribute of the img tag.
Is it possible to solve the problem?
Thank you!
The solution is to mark every p:graphicImage and his h:outputLink with a custom id.
<c:forEach items="#{myController.images}" var="img" begin="0" class="hidden-xs" varStatus="loop">
<h:outputLink id="aInsideLightbox#{loop.index+1}" class="fancybox imgCVLGalleryDetail hidden-xs" rel="group">
<p:graphicImage id="imgInsideLightbox#{loop.index+1}" value="#{applicationScopedBean.imagesFromDb}" class="img">
<f:param name="imageId" value="#{img.imageWrapper.id}" />
</p:graphicImage>
</h:outputLink>
</c:forEach>
and then in the front-end side when the page is ready
<h:outputScript library="js" name="external.js"/>
<script>
$(document).ready(function () {
setUrlInTheFancyboxLinkAndImage();
setTypeImageInFancybox();
});
</script>
and in an external .js file the following functions.
function setUrlInTheFancyboxLinkAndImage() {
for (i = 0; i < 20; i++) {
$imgToImprove = document.getElementById("imgInsideLightbox" + i);
if ($imgToImprove !== null) {
$aToImprove = document.getElementById("aInsideLightbox" + i);
if ($aToImprove !== null) {
$aToImprove.setAttribute("href", $imgToImprove.getAttribute("src"));
}
}
}
}
function setTypeImageInFancybox() {
$(".fancybox").fancybox({
type: 'image',
openEffect: 'none',
closeEffect: 'none'
}); }

Show progress percentage of h:inputFile upload

I found this very nice example of file upload using JSF 2.2. Is it possible to add progress bar with percent of file upload or total uploaded bytes?
<script type="text/javascript">
function progressBar(data) {
if (data.status === "begin") {
document.getElementById("uploadMsgId").innerHTML="";
document.getElementById("progressBarId").setAttribute("src", "./resources/progress_bar.gif");
}
if (data.status === "complete") {
document.getElementById("progressBarId").removeAttribute("src");
}
}
</script>
<h:messages id="uploadMsgId" globalOnly="true" showDetail="false" showSummary="true" style="color:red"/>
<h:form id="uploadFormId" enctype="multipart/form-data">
<h:inputFile id="fileToUpload" required="true" requiredMessage="No file selected ..." value="#{uploadBean.file}"/>
<h:message showDetail="false" showSummary="true" for="fileToUpload" style="color:red"/>
<h:commandButton value="Upload" action="#{uploadBean.upload()}">
<f:ajax execute="fileToUpload" onevent="progressBar" render=":uploadMsgId #form"/>
</h:commandButton>
</h:form>
<div>
<img id="progressBarId" width="250px;" height="23"/>
</div>
Bean:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.http.Part;
#Named
#RequestScoped
public class UploadBean {
private static final Logger logger = Logger.getLogger(UploadBean.class.getName());
private Part file;
public Part getFile() {
return file;
}
public void setFile(Part file) {
this.file = file;
}
public void upload() {
if (file != null) {
logger.info("File Details:");
logger.log(Level.INFO, "File name:{0}", file.getName());
logger.log(Level.INFO, "Content type:{0}", file.getContentType());
logger.log(Level.INFO, "Submitted file name:{0}", file.getSubmittedFileName());
logger.log(Level.INFO, "File size:{0}", file.getSize());
try (InputStream inputStream = file.getInputStream(); FileOutputStream outputStream = new FileOutputStream("C:" + File.separator + "jsf_files_test_for_delete" + File.separator +file.getSubmittedFileName())) {
int bytesRead = 0;
final byte[] chunck = new byte[1024];
while ((bytesRead = inputStream.read(chunck)) != -1) {
outputStream.write(chunck, 0, bytesRead);
}
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Upload successfully ended!"));
} catch (IOException e) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Upload failed!"));
}
}
}
}
Is this possible without additional JavaScript code? Only with JSF?
I found that the Malsup Form plugin for jQuery is fairly simple and has good documentation and demo code (therefore fairly easy to use to Ajaxify a progress bar) if you are prepared to go the jQuery (Javascript) route. (Of course, other plugins also exist, like the BlueImp file uploader plugin which has a lot more possibilities, but may not be quite that easy to use.)
For a "JSF-only" solution, BalusC recommends using a JSF component library like Primefaces - which is probably a better option - it is recommended to read his comments and links he provides which explain reasoning behind the preference for one technology over the other.
=== Added example ===
Here is a very basic example, using the Malsup Form plugin and jQuery, that demonstrates the progress bar. (It also handles other fields on the form, if one wants that, but do read up on the pros&cons of the different enctype settings in the <form> element.) Note that a <div> with a progress bar and a text label indicating progress percentage is shown, and another <div> showing some text on completion of the process - any of these elements may be omitted or otherwise customized. These <div>s are styled via CSS and updated by various event handlers in the Javascript. No work is done in the Java backing bean.
Note:
I hope this is obvious, but the *.js files are saved in the directory <my-eclipse-project>/WebContent/resources/js/ for the <h:outputScript> tags to work correctly.
1. XHTML view, including CSS and Javascript
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.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>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Demo File upload with progress</title>
<style>
.progress {
position: relative;
width: 400px;
border: 1px solid #ddd;
padding: 1px;
border-radius: 3px;
}
.bar {
background-color: #B4F5B4;
width: 0%;
height: 20px;
border-radius: 3px;
}
.percent {
position: absolute;
display: inline-block;
top: 3px;
left: 48%;
}
</style>
<h:outputScript target="head" library="js" name="jquery.js" />
<h:outputScript target="head" library="js" name="jquery.form.js" /><!-- http://jquery.malsup.com/form/ -->
<h:outputScript target="body">
//<![CDATA[
jQuery(document).ready(function() {
var bar = jQuery('.bar');
var percent = jQuery('.percent');
var status = jQuery('#status');
jQuery('#formid').ajaxForm({
beforeSend: function() {
status.empty();
var percentVal = '0%';
bar.width(percentVal)
percent.html(percentVal);
},
uploadProgress: function(event, position, total, percentComplete) {
var percentVal = percentComplete + '%';
bar.width(percentVal)
percent.html(percentVal);
},
success: function() {
var percentVal = '100%';
bar.width(percentVal)
percent.html(percentVal);
},
complete: function(xhr) {
status.html(xhr.statusText);
}
});
});
//]]>
</h:outputScript>
</h:head>
<h:body>
<h:form id="formid" enctype="multipart/form-data" method="post">
<h1>Demo File upload with progress</h1>
<h:messages globalOnly="true" tooltip="true" />
<h:inputFile id="fileupload" name="fileupload" value="#{uploadBean.file}" />
<div class="progress">
<div class="bar"></div>
<div class="percent">0%</div>
</div>
<div id="status"></div>
<br />
<h:inputText value="#{uploadBean.field}"></h:inputText>
<br />
<h:commandButton id="submit" action="#{uploadBean.submit}" value="Submit" />
</h:form>
</h:body>
</html>
2. Backing bean
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.servlet.http.Part;
#ManagedBean
#ViewScoped
public class UploadBean implements Serializable {
private static final long serialVersionUID = 1L;
private String field;
private Part file;
/** Constructor */
public UploadBean() {}
/** Action handler */
public String submit() {
// the file is already uploaded at this point
// TODO whatever you need to do with the file and other form values
return ""; // ... or another view
}
// TODO getters and setters for fields
}

Warning: This page calls for XML namespace http://www.facebook.com/2008/fbml declared with prefix fb but no taglibrary exists for that namespace

I am developing an application for FB Login with website using Javascript. I tried in html it works fine. when i convert into JSF it gives an error.
This is my fbLogin.xhtml 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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:fb="http://www.facebook.com/2008/fbml">
<h:head>
<title>FB Login</title>
<link rel="stylesheet" type="text/css" href="./xmlhttp/css/rime/rime.css"/>
</h:head>
<h:body styleClass="ice-skin-rime">
<fb:login-button scope="email"></fb:login-button>
<script>
window.fbAsyncInit = function() {
FB.init({
appId : '<APP_ID>',
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Additional initialization code here
showMe = function(response) {
if (response.status !== 'connected') {
div.innerHTML = '<em>Not Connected</em>';
} else {
FB.api('/me', function(response) {
var i=0;
for (var key in response) {
i++;
switch(i){
case 1: document.getElementById("formId:id").value=response[key]; break;
case 2: document.getElementById("formId:name").value=response[key]; break;
case 5: document.getElementById("formId:link").value=response[key]; break;
case 6: document.getElementById("formId:userName").value=response[key]; break;
case 19: document.getElementById("formId:email").value=response[key]; break;
}
}
});
}
};
FB.getLoginStatus(function(response) {
showMe(response);
FB.Event.subscribe('auth.authResponseChange', showMe);
});
};
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
</script>
<h:form id="formId">
<table>
<tr><td><a>ID : <h:inputText id="id" value="#{fbLogin.id}" /> </a></td></tr>
<tr><td><a>Name : <h:inputText id="name" value="#{fbLogin.name}" /> </a></td></tr>
<tr><td><a>Link : <h:inputText id="link" value="#{fbLogin.link}" /> </a></td></tr>
<tr><td><a>User Name : <h:inputText id="userName" value="#{fbLogin.userName}" /> </a></td></tr>
<tr><td><a>E-Mail : <h:inputText id="email" value="#{fbLogin.email}" /> </a></td></tr>
<tr><td><h:commandButton value="Register" action="#{fbLogin.Display}" /></td></tr>
</table>
</h:form>
</h:body>
</html>
The reason for writing code with JSF is, i need to get user information in to my backBean for store into database.
when i try to run this app, i got warning in browser as :
Warning: This page calls for XML namespace http://www.facebook.com/2008/fbml declared with prefix fb but no taglibrary exists for that namespace.
What is the error in my code?
You will get this when you have set javax.faces.PROJECT_STAGE to Development in webapp's web.xml and Facelets encounters a XML namespace which it could not resolve to a JSF compatible tag library. This warning is just displayed to inform a (starting) developer about a possible unforeseen typo in the XML namespace or mistake in tag library configuration.
However, the XML namespace in question in this particular case actually referring an external Facebook JavaScript API, not a JSF tag library such as PrimeFaces, OmniFaces, etc. Your code is completely fine.
You can just ignore this warning. This warning won't appear when you set the JSF project stage back to Production, or when you remove the whole context parameter (it defaults to Production already).

Manage back and forward in Richfaces

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.

Resources