I'm working with a web application in JSF in which I came across a situation where an item is selected in a dropdown list <h:selectOneMenu></<h:selectOneMenu>
, a corresponding value (id) is returned to the JSF managed bean with the help of Ajax <f:ajax></f:ajax>
and based on that id corresponding rows (data) are retrieved from MySql database and displayed on JSF page dynamically at run time in dataTable <h:dataTable></h:dataTable>
. It is working with no problem at all. Now, some operations like insert, update, delete etc need to be performed on that data (which are displayed on the dataTable). On each row of the dataTable, I have added two buttons (with two columns), one for edit and the other for delete (It is extremely crucial to note that these buttons are generated at run time with Ajax). Now, when I click on one of these buttons in turn, nothing happens (It is like dead buttons).
For the sake of simplicity and demonstration here, I have prepared as simple code as possible that somewhat corresponds to the real application.
JSF page code goes here with as minimum tags as possible.
<?xml version='1.0' encoding='UTF-8' ?>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Simple Demo</title>
</h:head>
<h:body>
<h:form>
<h:selectOneMenu id="listItems" value="#{ajaxCommandButtonDemo.listItems}">
<f:selectItem id="item1" itemLabel="Item1" itemValue="1"/>
<f:selectItem id="item2" itemLabel="Item2" itemValue="2"/>
<f:ajax event="valueChange" execute="dataItems" render="dataItems"/>
</h:selectOneMenu>
<br/><br/><br/>
<h:dataTable id="dataItems" var="row" value="#{ajaxCommandButtonDemo.dataItems}" border="1">
<f:facet id="header" name="header">
<h:outputText value="Data"/>
</f:facet>
<h:column>
<f:facet name="header">
Data Items
</f:facet>
<h:outputText id="txt1" value="#{row.toString()}"/>
<h:commandButton value="Submit" id="btnSubmit" actionListener="#{ajaxCommandButtonDemo.action}">
<f:ajax event="action" execute="dataItems" render="dataItems"/>
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
And here is the corresponding JSF managed bean.
package demo;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class AjaxCommandButtonDemo
{
private String listItems="";
private List<String> dataItems=null;
public AjaxCommandButtonDemo() {}
public String getListItems() {
return listItems;
}
public void setListItems(String listItems) {
this.listItems = listItems;
}
public List<String> getDataItems() {
if(listItems.equals("1"))
{
dataItems=new ArrayList<String>();
dataItems.add("dataItem1/Item1");
dataItems.add("dataItem2/Item1");
dataItems.add("dataItem3/Item1");
}
else if(listItems.equals("2"))
{
dataItems=new ArrayList<String>();
dataItems.add("dataItem1/Item2");
dataItems.add("dataItem2/Item2");
dataItems.add("dataItem3/Item2");
}
return dataItems;
}
public void setDataItems(List<String> dataItems) {
this.dataItems = dataItems;
}
public void action(){
System.out.println("Button clicked.");
}
}
In this simple code snippet, when this JSF page is loaded for the first time, it simply displays a dropdown List with only two items in it Item1 and Item2 (being populated at page load time) and a dataTable with no data within it. When an item in the dropdown list selected, suppose Item1 is selected, it simply displays the following data in the dataTable.
dataItem1/Item1 Submit
dataItem2/Item1 Submit
dataItem3/Item1 Submit
and when Item2 in the dropdown list is selected, it displays the following data in the dataTable.
dataItem1/Item2 Submit
dataItem2/Item2 Submit
dataItem3/Item2 Submit
In the first column of the dataTable data from the ArraList is displayed which is bound to this dataTable and the second column displays simply a JSF CommandButton <h:commandButton></h:commandButton>
. [I avoided displaying data from the database here for the sake of simplicity].
When an item in the dropdown list is selected, corresponding value either 1 or 2 is returned to the JSF managed bean in the listItems property, here it is
<h:selectOneMenu id="listItems" value="#{ajaxCommandButtonDemo.listItems}">
<f:selectItem id="item1" itemLabel="Item1" itemValue="1"/>
<f:selectItem id="item2" itemLabel="Item2" itemValue="2"/>
<f:ajax event="valueChange" execute="dataItems" render="dataItems"/>
</h:selectOneMenu>
and it renders dataTable with the help of Ajax on valueChange event.
<f:ajax event="valueChange" execute="dataItems" render="dataItems"/>
and based on the value passed to the listItems in the JSF managed bean, ArraList is populated and returned to the dataTable.
public List<String> getDataItems() {
if(listItems.equals("1"))
{
dataItems=new ArrayList<String>();
dataItems.add("dataItem1/Item1");
dataItems.add("dataItem2/Item1");
dataItems.add("dataItem3/Item1");
}
else if(listItems.equals("2"))
{
dataItems=new ArrayList<String>();
dataItems.add("dataItem1/Item2");
dataItems.add("dataItem2/Item2");
dataItems.add("dataItem3/Item2");
}
return dataItems;
}
public void setDataItems(List<String> dataItems) {
this.dataItems = dataItems;
}
Now, when I clicked on the command button in the dataTable whose action is bound to the action method in managed bean,
public void action(){
System.out.println("Button clicked.");
}
a message "Button clicked" should be displayed on the console through the statement System.out.println("Button clicked."); but nothing happens. Why?
It was all most made sure that there was no problem other than this.
Well, I kept trying and found that when I modified my JSF ManagedBean as follows, it worked...!!!
@ManagedBean
@ViewScoped
public class AjaxCommandButtonDemo implements Serializable
{
//ManagedBean code here which was posted above.
}
I just designated the ManagedBean with the view scope and implemented the Serializable interface, it worked fine and displayed the message "Button clicked." on the console as expected but I'm unable to understand why this is happening. Why these modifications are required?