I am using #ViewScoped Bean for small CRUD application I have a edit and view page but when I click buttons (edit) it will render edit form. After edit form appears the save button or cancel button does not call the function but renders the whole page. The actionListener's function is not called at all and everthing is initialized. Is something wrong with my bean and page?? I am using JSF 2 with richfaces and facelet.
//ViewScoped Bean
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.legendMgr.Legend;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
/**
*
* #author kitex
*/
#ManagedBean(name = "legendbean")
#ViewScoped
public class LegendController implements Serializable {
LegendDTO legendDTO;
String selectedLegend;
List<LegendDTO> legendDTOs;
boolean edit;
public List<LegendDTO> getLegendDTOs() {
return legendDTOs;
}
public void setLegendDTOs(List<LegendDTO> legendDTOs) {
this.legendDTOs = legendDTOs;
}
#PostConstruct
void initialiseSession() {
FacesContext.getCurrentInstance().getExternalContext().getSession(true);
}
public LegendController() {
if (!edit) {
legendDTO = new LegendDTO();
legendDTO.getList().add(new Legend());
legendDTOs = getLegends();
}
}
public String getSelectedLegend() {
return selectedLegend;
}
public void setSelectedLegend(String selectedLegend) {
this.selectedLegend = selectedLegend;
}
public boolean isEdit() {
return edit;
}
public void setEdit(boolean edit) {
this.edit = edit;
}
public LegendDTO getLegendDTO() {
return legendDTO;
}
public void setLegendDTO(LegendDTO legendDTO) {
this.legendDTO = legendDTO;
}
public void addLegendRange() {
Logger.getLogger(LegendController.class.getName()).warning("List Size " + legendDTO.getList().size());
legendDTO.getList().add(new Legend());
Logger.getLogger(LegendController.class.getName()).warning("List Size " + legendDTO.getList().size());
}
public void removeLegendRange(Legend legend) {
if (legendDTO.getList().size() != 1) {
legendDTO.getList().remove(legend);
}
}
public String saveLegend() {
Logger.getLogger(LegendController.class.getName()).warning("Save Legend Edit" + edit);
LegendDAO dao = new LegendDAO();
if (dao.addLegend(legendDTO, edit)) {
edit = false;
Logger.getLogger(LegendController.class.getName()).warning("Save Legend Edit" + edit);
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Could Not Save Confim if you have already defined Legend " + legendDTO.getLegendName() + "!"));
}
return "";
}
public String cancel() {
edit = false;
legendDTO = new LegendDTO();
legendDTO.getList().add(new Legend());
return "";
}
public List<LegendDTO> getLegends() {
LegendDAO dao = new LegendDAO();
return dao.getLegendDTO();
}
//All function from here are for legend delete
public void deleteLegendType(LegendDTO dto) {
LegendDAO dao = new LegendDAO();
if (dao.deleteLegendType(dto.getLegendName())) {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Deleted !"));
} else {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Deleted Error !"));
}
}
//All function from here is to legend edit
public void editLegendType(LegendDTO dto) {
edit = true;
Logger.getLogger(LegendController.class.getName()).warning("DTO : " + dto.legendName);
legendDTO = dto;
LegendDAO dao = new LegendDAO();
Logger.getLogger(LegendController.class.getName()).warning("Edit dto set");
try {
List<Legend> legends = dao.getDetailForEditLegend(dto.getLegendName());
if (legends == null || legends.isEmpty()) {
dto.getList().add(new Legend());
} else {
dto.setList(legends);
}
} catch (SQLException ex) {
Logger.getLogger(LegendController.class.getName()).warning("SQL EXception has occoured");
}
Logger.getLogger(LegendController.class.getName()).warning("In Edit Legend Function The size of list" + dto.getList().size());
}
}
//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:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
<ui:composition template="/legendTemplate.xhtml">
<ui:define name="windowTitle">Change Legend</ui:define>
<ui:define name="content">
<h:messages globalOnly="true"/>
<rich:panel id="firstPanel">
<h:form id="nis_viewLegend">
<rich:dataTable id="data_tbl" value="#{legendbean.legendDTOs}" var="legendDTOvar" style="width:100%" rendered="#{!legendbean.edit and not empty legendbean.legendDTOs}">
<rich:column>
<f:facet name="header">
<h:outputText value="Description"/>
</f:facet>
<h:outputText value="#{legendDTOvar.desc}"/>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Legend Type"/>
</f:facet>
<h:outputText value="#{legendDTOvar.legendName}"/>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Legend Type"/>
</f:facet>
<h:outputText value="#{legendDTOvar.legendFor}"/>
</rich:column>
<rich:column>
<a4j:commandLink value="Delete" actionListener="#{legendbean.deleteLegendType(legendDTOvar)}" render=":firstPanel"/>
<h:outputText value="/"/>
<a4j:commandLink value="Edit" actionListener="#{legendbean.editLegendType(legendDTOvar)}" render=":secondPanel :editLegendForm :nis_viewLegend"/>
</rich:column>
</rich:dataTable>
</h:form>
</rich:panel>
<rich:panel id="secondPanel">
<h:form id="editLegendForm" rendered="#{legendbean.edit}">
<h:outputText value="Legend Name"/><br/>
<h:inputText value="#{legendbean.legendDTO.legendName}" readonly="true"/><br/>
<h:outputText value="Description"/><br/>
<h:inputText value="#{legendbean.legendDTO.desc}"/><br/>
<h:outputText value="Legend For"/><br/>
<h:inputText value="#{legendbean.legendDTO.legendFor}"/><br/>
<br/>
<h:outputText value="Range" />
<rich:dataTable id="editDataPnl" value="#{legendbean.legendDTO.list}" var="legend" style="width:100%">
<rich:column>
<f:facet name="header">
<h:outputText value="SN"/>
</f:facet>
<h:inputText value="#{legend.sn}"/>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Description"/>
</f:facet>
<h:inputText value="#{legend.desc}"/>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Lower Range"/>
</f:facet>
<h:inputText value="#{legend.lowerRange}"/>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Upper Range"/>
</f:facet>
<h:inputText value="#{legend.upperRange}"/>
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Color"/>
</f:facet>
<h:inputText value="#{legend.color}"/>
</rich:column>
<rich:column>
<a4j:commandLink value="Add" actionListener="#{legendbean.addLegendRange}" render=":secondPanel"/>
<h:outputText value=" / "/>
<a4j:commandLink value="Remove" actionListener="#{legendbean.removeLegendRange(legend)}" render=":secondPanel"/>
</rich:column>
</rich:dataTable>
<br/>
<center>
<a4j:commandButton value="SAVE" action="#{legendbean.saveLegend()}" render=":firstPanel :secondPanel"/>
<a4j:commandButton value="CANCEL" action="#{legendbean.cancel()}" render=":firstPanel :secondPanel"/>
</center>
</h:form>
</rich:panel>
</ui:define>
</ui:composition>
</h:body>
</html>
In ViewScope, once the view is built, for example form.xhtml, its data will last as long you do not go away from this view. To stay in the same view you should call methods that has return type void (which are usually used in actionListener property) or return null, in case of returning an outcome for navigation.
Method expression
In your case your methods are void but instead of passing it to the action listener you're calling it in the view.
Try changing similar code like this:
<a4j:commandButton value="SAVE" actionListener="#{legendbean.saveLegend()}" render="mainPnl"/>
To this:
<a4j:commandButton value="SAVE" actionListener="#{legendbean.saveLegend}" render="mainPnl"/>
As actionListener property already expects a method expression.
Form inside dataTable
Also I noticed you have a form inside your dataTable. That could lead to strange behavior because your form has an id it will be repeated in the resulting page. For that you should try placing the form outside the dataTable.
Even better you could have only one form enclosing the entire code as nested forms are invalid HTML code.
I would suggest you check your legendTemplate.xhtml against nested forms too.
Bean construction
In order to initialize your bean state it is recommended to use a #PostContruct method instead of the bean constructor.
Try changing from this:
public LegendController() {
legendDTO = new LegendDTO();
legendDTO.getList().add(new Legend());
}
To this:
#PostConstruct
public void reset() {
legendDTO = new LegendDTO();
legendDTO.getList().add(new Legend());
}
And delete your constructor.
Your bean data should be kept as long as you're in the same view (aka .xhtml page).
I hope it helps.
I am having the same problem. I don't think the answers above really address the question. He is not having a problem as a result of submitting any forms - pressing those buttons themselves results in the whole page re-rendering, which means that the reference to the view state is already gone before the button is pressed. This is what I am observing as well. For me, it only happens when there are a lot of large search results, and simply re-submitting the same search I just did re-renders the page (without executing the search). I believe the problem has to do with a limit on the amount of data that can be passed to the server in a form: in view scope, all of the data is serialized and passed around in one long hidden value as a value in the form. If that value is too long the server won't accept it and, therefore, will not remember the previous state.
I know this is not definitive, but this is only thread out there on this problem I can find so I hope it helps shed light for others or inspires better information. If you have something more definitive please let us know.
Edit: I am convinced now that this was the problem. My model bean had a reference to a file blob. Once I replaced that reference with a boolean (only needed to know if it existed) the problem went away. Try passing around references to your DTOs/DAOs instead of the objects themselves, or mark them as "transient" where you don't need them to persist. Or, if possible, lighten the objects as I did.
Did you try to return null for functions saveLegend() and cancel() instead of returning empty string?
public String saveLegend() {
---------
return null;
}
public String cancel() {
----------
return null;
}
Return can also be void for ajax request. But if I remember it correctly for richfaces returning null is the only solution. Give it a try. :)
The cancel() works as it reinitialize the bean.
As answered by Bento you cannot pass values using actionListener. Use action instead.
Further Reading:
JSF 2 ViewScope questions
JSF2 Action parameter
Differences between action and actionListener
Related
Search Parameters are first name and last name while when i click on the search it is getting the value because i m printing then on console but not displaying using datatable. the code that i have written for this purpose is given below:
studentSearch.xhtml
<!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>
<title>Search the Student Here</title>
</h:head>
<h:body>
<h:form id="searchForm">
<center><b>Search the Student Details Here</b></center>
<h:panelGrid id="searchStudent" columns="4">
<h:outputLabel id="searchText" value="Enter the firstname of the Student:"></h:outputLabel>
<h:inputText id="searchfName" value="#{student.firstName}"></h:inputText>
<h:outputLabel id="searchlText" value="Enter the lastname of the Student:"></h:outputLabel>
<h:inputText id="searchfName" value="#{student.lastName}"></h:inputText>
<h:commandButton value="Search Student" action="#{student.fullInfoByname}"></h:commandButton>
<h:dataTable value="#{searchBean.lstSearch}" var="student">
<h:column>
<f:facet name="header">
Student School ID
</f:facet>
<h:outputText value="#{student.studentSchoolID}"></h:outputText>
</h:column>
<h:column>
<f:facet name="header">
Student First Name
</f:facet>
#{student.firstName}
</h:column>
<h:column>
<f:facet name="header">
Student Last Name
</f:facet>
#{student.lastName}
</h:column>
<h:column>
<f:facet name="header">
Father's Name
</f:facet>
#{student.fatherName}
</h:column>
<h:column>
<f:facet name="header">
Mother's Name
</f:facet>
#{student.motherName}
</h:column>
<h:column>
<f:facet name="header">
Gender
</f:facet>
#{student.gender}
</h:column>
</h:dataTable>
</h:panelGrid>
</h:form>
</h:body>
</html>
Methods used for this purpose
StudentDao.java method
public List<Student> getStudentByName(String fname,String lname)
{
Transaction trans=null;
Session session=HiberUtil.getSessionFactory().openSession();
try{
trans=session.beginTransaction();
String queryString="from Student where firstName = :id or lastName = :idd";
Query query=session.createQuery(queryString);
query.setString("id", fname);
query.setString("idd", lname);
List<Student> list=query.list();
if(list.size()>0)
{
return list;
}
}catch(Exception e)
{
e.printStackTrace();
}
return null;
}
in Student.java class
public void fullInfoByname()
{
StudentDao dao=new StudentDao();
List<Student> list=new ArrayList<Student>();
List<Student> lc=dao.getStudentByName(firstName, lastName);
for(int i=0;i<lc.size();i++)
{
System.out.println(lc.get(0).firstName);
this.studentSchoolID=lc.get(0).studentSchoolID;
System.out.println(lc.get(0).studentSchoolID);
this.lastName=lc.get(0).lastName;
System.out.println(lc.get(0).lastName);
this.fatherName=lc.get(0).fatherName;
System.out.println(lc.get(0).fatherName);
this.motherName=lc.get(0).motherName;
System.out.println(lc.get(0).motherName);
this.gender=lc.get(0).gender;
System.out.println(lc.get(0).gender);
this.fee=lc.get(0).fee;
this.course=lc.get(0).course;
this.session=lc.get(0).session;
this.hobbies=lc.get(0).hobbies;
this.email=lc.get(0).email;
this.phoneNumber=lc.get(0).phoneNumber;
this.addressOne=lc.get(0).addressOne;
this.addressTwo=lc.get(0).addressTwo;
this.city=lc.get(0).city;
this.state=lc.get(0).state;
this.zip=lc.get(0).zip;
this.country=lc.get(0).country;
this.status=lc.get(0).status;
}
list.addAll(lc);
System.out.println("list Size="+list.size());
if(list.size()>0)
{
SearchStudent sc=new SearchStudent();
sc.setLstSearch(list);
}
}
Now in the last i m putting the list sc.setLstSearch after getting it in the xhtml page it is not displaying searched values while if i m getting the size of the variable lstSearch then it is giving correct size but not deisplaying it.
the list created in the searchBean is as follow.
package com.school.entity;
import java.util.Iterator;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean(name="searchBean")
#SessionScoped
public class SearchStudent {
private List<Student> lstSearch;
public List<Student> getLstSearch() {
return lstSearch;
}
public void setLstSearch(List<Student> lstSearch) {
this.lstSearch = lstSearch;
//System.out.println(lstSearch);
//for checking how many values coming from the list
/*Iterator<Student> itr=lstSearch.iterator();
while(itr.hasNext())
{
System.out.println(itr.next());
}*/
}
}
The problem is in Student class, you should not create SearchStudent class using new operator. Try to inject it using managedProperty and set it. If you don't know how to use it please follow this tutorial http://www.mkyong.com/jsf2/injecting-managed-beans-in-jsf-2-0/
update:
After your comment what I noticed is, Student.java is an entity class. Its not good to place business logic in entity class and also injection are not permitted in entity classes. So update your code as follows
Move the method public void fullInfoByname() to managed bean i.e SearchStudent class.
Create two properties firstName and lastName in SearchStudent class
Set the value of input controls for search to the property of SearchStudent class.
Change the action method in search form to the method fullInfoByname in SearchStudent.
After this you can directly call this.setLstSearch(list); in fullInfoByname method
I have a data table that will display a detail dialog on row select event. However, the dialog does not show any values of the selected object. I can see that the selected object is properly set during debug session.
The table consists of rows of students and it is suppose to display a popup dialog showing detailed information on row selection event.
The StudentBean:
#Named(value = "studentBean")
#SessionScoped
public class StudentBean {
#Inject
private UserFacade userFacade;
private List<User> studentList;
private User selectedStudent;
public StudentBean() {
}
#PostConstruct
public void init() {
studentList = userFacade.findAll();
}
public List<User> getStudentList() {
return studentList;
}
public void setStudentList(List<User> studentList) {
this.studentList = studentList;
}
public User getSelectedStudent() {
return selectedStudent;
}
public void setSelectedStudent(User student) {
this.selectedStudent = student;
}
public void onRowSelect(SelectEvent event) {
}
public void onRowUnselect(UnselectEvent event) {
//FacesMessage msg = new FacesMessage("Student Unselected", ((User) event.getObject()).getFirstName());
//FacesContext.getCurrentInstance().addMessage("messages", msg);
}
}
The Facelet page:
<?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:ui="http://java.sun.com/jsf/facelets"
xmlns:h ="http://java.sun.com/jsf/html"
xmlns:p ="http://primefaces.org/ui">
<body>
<ui:composition template="./layout.xhtml">
<ui:define name="content">
<h:form id="studentForm">
<p:dataTable var="student" value="#{studentBean.studentList}"
selectionMode="single"
selection="#{studentBean.selectedStudent}" rowKey="#{student.id}">
<p:ajax event="rowSelect" listener="#{studentBean.onRowSelect}"
update=":studentForm:studentDetail" oncomplete="studentDialog.show()"
global="true" immediate="true"
/>
<p:ajax event="rowUnselect" listener="#{studentBean.onRowUnselect}" />
<p:column headerText="First Name">
<h:outputText value="#{student.firstName}" />
</p:column>
<p:column headerText="Last Name">
<h:outputText value="#{student.lastName}" />
</p:column>
<p:column headerText="Student ID">
<h:outputText value="#{student.studentid}" />
</p:column>
</p:dataTable>
<p:dialog id="dialog" header="Student Detail" widgetVar="studentDialog" resizable="false"
showEffect="fade" hideEffect="fade" appendToBody="true">
<h:panelGrid id="studentDetail" columns="2" cellpadding="4">
<h:outputText value="First Name: " />
<h:outputText value="#{studentBean.selectedStudent.firstName}" />
<h:outputText value="Last Name: " />
<h:outputText value="#{studentBean.selectedStudent.lastName}" />
</h:panelGrid>
</p:dialog>
</ui:define>
</ui:composition>
</body>
</html>
I'm following the Car data table example from the Primefaces Showcase page. It seems so simple there but I can't seem to display the selectedStudent information no matter what I do. The dialog shows up fine but the firstName and lastName values are empty.
I tried the following:
Putting the dialog into another form
Use process="#form"
Use process=":studentForm:studentDetail"
What am I doing wrong?
Primefaces 3.3.1,
Glassfish 3.1.2
I removed global="true" immediate="true", unused listeners
from p:ajax, synchronized rowKey="#{student.id}"
with expression from "Student ID" column and populated
studentList inside #PostConstruct init() function not knowing how yours userFacade code is, and it works.
I have create a test project with JSF2.0 and richfaces. I am trying to plot chart. Now, I got value from database to bean and to datatable. Now when I wanted to pass this value to javascript varible and found this answer from The BalusC very userful. It works fine but the value that javascript variable gets after oncomplete="jsonDemo('#{kpilist.json}')". i.e. the value of #{kpilist.json} is not up-to-date it's last one.
I have printed the value of #{kpilist.json}. If it's printed afer datatabe the value is current. If it's printed before datatable it's last value. Any way since oncomplete attribute of a4j:ajax executes after eveything is completed why doesn't #{kpilist.json} show latest value? What is the order of execution of various listener and oncomplete attributes of richfaces and jsf component?
My Managed Bean:
#ManagedBean(name = "kpilist")
#ViewScoped
public class KPIListController implements Serializable {
private static final long serialVersionUID = 1L;
boolean state = true;
String selectedKPIType;
String selectKPITime = "D";
boolean renderDatatable;
String json;
public String getJson() {
return json;
}
public boolean isRenderDatatable() {
return renderDatatable;
}
public void setRenderDatatable(boolean renderDatatable) {
this.renderDatatable = renderDatatable;
}
public boolean isState() {
return state;
}
public List<String> showViewList() {
Logger.getLogger(KPIListController.class.getName()).warning("Show view List:");
KPIDAO kpiDAO = new KPIDAO();
try {
Logger.getLogger(KPIListController.class.getName()).info("Into show view List ---select One");
return kpiDAO.showViewList(selectKPITime);
} catch (SQLException ex) {
ex.printStackTrace();
Logger.getLogger(KPIListController.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
public void setState(boolean state) {
this.state = state;
}
public String getSelectedKPIType() {
return selectedKPIType;
}
public void setSelectedKPIType(String selectedKPIType) {
this.selectedKPIType = selectedKPIType;
}
public String getSelectKPITime() {
return selectKPITime;
}
public void setSelectKPITime(String selectKPITime) {
this.selectKPITime = selectKPITime;
}
public List<KPI> getKPI() {
Logger.getLogger(KPIListController.class.getName()).warning("Get KPI Values:");
KPIDAO kpiDAO = new KPIDAO();
List<KPI> kpiList = new ArrayList<KPI>();
try {
kpiList = kpiDAO.getKPI(selectedKPIType);
Logger.getLogger(KPIListController.class.getName()).warning("KPI List:"+kpiList.size());
} catch (SQLException ex) {
ex.printStackTrace();
return null;
}
Gson gson = new Gson();
json= gson.toJson(kpiList);
return kpiList;
}
public void resetFormValues() {
Logger.getLogger(KPIListController.class.getName()).warning("Reset form:");
selectedKPIType = "--";
}
}
My View:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
</h:head>
<h:body>
<ui:composition template="/contentTemplate.xhtml">
<ui:define name="windowTitle">KPI Index</ui:define>
<ui:define name="content" >
<h:outputScript name="js/graphics/jquery.js"/>
<h:outputStylesheet name="/css/jquery-ui-1.8.22.custom.css"/>
<h:outputScript name="js/graphics/jquery-ui-1.8.22.custom.min.js"/>
<h:outputScript name="js/OpenLayers/OpenLayers.js"/>
<h:outputScript name="js/graphics/raphael-min.js"/>
<h:outputScript name="js/graphics/canvg.js"/>
<h:outputScript name="js/graphics/paths.js"/>
<h:outputScript name="js/graphics/draw.js"/>
<h:form id="ins_sel_form">
<h:outputText value="KPI TIME FRAME"/>
<h:selectOneRadio value="#{kpilist.selectKPITime}" >
<f:selectItem itemLabel="DAILY" itemValue="D" />
<f:selectItem itemLabel="WEEKLY" itemValue="W" />
<f:selectItem itemLabel="LAST WEEK" itemValue="LW" />
<a4j:ajax event="change" render="ins_sel_form:selectOnemenu dataPnl" listener="#{kpilist.resetFormValues()}" />
</h:selectOneRadio>
<h:outputText value="Major KPI Type"/>
<h:selectOneMenu id="selectOnemenu" value="#{kpilist.selectedKPIType}" >
<f:selectItem itemValue="--" itemLabel="--"></f:selectItem>
<f:selectItems itemValue="#{item.toString()}" var="item" itemLabel="#{item.toString()}" value="#{kpilist.showViewList()}"/>
<a4j:ajax event="change" render="dataPnl" oncomplete="jsonDemo('#{kpilist.json}')" />
</h:selectOneMenu>
<h:outputText value="Show / Hide Map"/>
</h:form>
<rich:panel id ="dataPnl">
<rich:dataTable id="kpiValueTable" value="#{kpilist.KPI}" var="kpi" style="width:100%" rows="20" rendered="#{kpilist.selectedKPIType!=null and kpilist.selectedKPIType !='--' }" >
<rich:column>
<f:facet name="header" >
<h:outputText value ="Value"></h:outputText>
</f:facet>
<h:outputText value="#{kpi.KPIValue}"></h:outputText>
</rich:column>
</rich:dataTable>
JSON String : <h:outputText id="json" value ="#{kpilist.json}"/>
<center><rich:dataScroller for="kpiValueTable" rendered="#{kpilist.selectedKPIType!=null and kpilist.selectedKPIType!='--'}"/></center>
</rich:panel>
<rich:panel id="map" style="display: none;">
</rich:panel>
</ui:define>
</ui:composition>
</h:body>
</html>
Javascript:
function jsonDemo(jsonString){
console.log("Chart data already retrieved: " + jsonString);
var data = $.parseJSON(jsonString);
$.each(data,function(i,val){
console.log("The value of i: "+i+" The val: "+val.NCELLCLUSTER);
});
}
The EL expression in your oncomplete is evaluated at the moment the HTML/JS code is generated by JSF (thus, on the initial HTTP request). It's not evaluated at the moment the oncomplete is executed in JS as you seem to expect. It's not the webbrowser who evaluates EL expressions, it's the webserver. The oncomplete is by the way just executed after render. With a HTTP traffic debugger and a JS debugger (press F12 in Chrome/IE9/Firebug) you can easily track it.
There are several possibilities to solve this:
Just invoke a $.get() or $.getJSON() in jQuery and do the job in a normal servlet instead, or better, a JAX-RS webservice.
function jsonDemo() {
$.getJSON("servletURL", function(jsonData) {
// ...
});
}
Replace the oncomplete by some <h:outputScript> which you render/update by ajax.
<a4j:ajax ... render="json" />
...
<h:panelGroup id="json">
<h:outputScript rendered="#{not empty bean.json}">jsonDemo(#{bean.json});</h:outputScript>
</h:panelGroup>
Unrelated to the concrete problem, you've there by the way a conceptual mistake as to passing around JSON data. You're stringifying it while passing as argument like so jsonDemo('#{kpilist.json}') and then you're parsing the JSON afterwards using $.parseJSON(). This makes no sense. Remove those singlequotes around the argument like so jsonDemo(#{kpilist.json}) and then you don't need that $.parseJSON() line anymore. The data is then already in JSON format.
Try changing from a4j:ajax to f:ajax
not sure if a4j:ajax works with plain JSF components
Im using primefaces version 3.1.1, Mojarra 2.1.3, Netbeans 7.0.1, Glassfish Server 3.1.
My test application is using a facelet template with top, left, content, right and bottom layout with raw divs and css. After user logs in with container managed jdbcrealm, they will be presented with the main index.html which use the said template.
I put a navigation menu on the left panel which will subsequently update center panel content with ajax upon clicking menuitem. The center panel will be updated dynamically in <ui:include> by using sessionScoped NavigationBean.
In one of the page clientList.xhtml, I put a <p:dataTable> with a button to view the detail by popping up a <p:dialog>. Im using a viewCoped bean to hold the data list displayed on the dataTable.
The problem is, when I click on the button to select a row in the last colum of every row, the dialog does not appear at all, and my p:ajaxStatus gif image kept on rolling unendingly. When I debug the program with netbeans, I notice the constructor is called again and the previous instance is gone after clicking the button.
This is my index.xhtml using facelets template.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<ui:composition template="/BySalesAutomationTemplate.xhtml">
<ui:define name="title">
<h:outputText value="Facelet Index Page"></h:outputText>
</ui:define>
<ui:define name="top">
TOP
</ui:define>
<ui:define name="left">
<ui:include src="users/menu#{request.isUserInRole('ADMIN') ? 'Admin' : 'User'}.xhtml" />
</ui:define>
<ui:define name="right">
<h:outputText value="Cuba2 daan"></h:outputText>
</ui:define>
<ui:define name="maincontent">
<c:if test="#{navigationBean.page!=null}">
<ui:include src="#{navigationBean.page}.xhtml" />
</c:if>
</ui:define>
<ui:define name="bottom">
<center>2012</center>
</ui:define>
</ui:composition>
</html>
This is the clientList.xhtml page which is displayed in the center panel of my index.xhtml upon clicking a link on the menu in the left panel.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Client Listing</title>
</h:head>
<h:body>
<p>Client List</p>
<h:form>
<h:commandButton action="#{authBackingBean.logout}" value="Logout" />
</h:form>
<f:view>
<h:form id="formdetail" prependId="false">
<p:ajaxStatus>
<f:facet name="start">
<h:graphicImage value="images/loading.gif" />
</f:facet>
<f:facet name="complete">
<h:outputText value="" />
</f:facet>
</p:ajaxStatus>
<p:growl id="growl" showDetail="true"/>
<p:dataTable id="dtClientList" value="#{saClientController.lazyModel}" rowsPerPageTemplate="10,20,30,50"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
paginatorAlwaysVisible="false" var="item" paginator="true" rows="10">
<f:facet name="header">
<h:outputText value="Client List"/>
</f:facet>
<p:column filterBy="#{item.idSaClient}">
<f:facet name="header">
<h:outputText value="IdSaClient"/>
</f:facet>
<p:commandLink action="#{saClientController.showDetails(item)}" value="#{item.idSaClient}" target=":maincontent"/>
</p:column>
<p:column filterBy="#{item.saClientName}">
<f:facet name="header">
<h:outputText value="saClientName"/>
</f:facet>
<h:outputText value="#{item.saClientName}"/>
</p:column>
<p:column filterBy="#{#item.saClientAddress}">
<f:facet name="header">
<h:outputText value="SaClientAddress"/>
</f:facet>
<h:outputText value="#{item.saClientAddress}"/>
</p:column>
<p:column style="width:40px">
<h:panelGrid columns="3" styleClass="actions" cellpadding="2">
<p:commandButton id="selectButton" update=":formdetail:display" oncomplete="clientDialog.show()" icon="ui-icon-search" title="View">
<f:setPropertyActionListener value="#{item}" target="#{saClientController.selectedSaClient}" />
</p:commandButton>
</h:panelGrid>
</p:column>
<f:facet name="footer">
<h:outputText value="Client List"/>
</f:facet>
</p:dataTable>
</h:form>
<p:dialog id="clientDialog" header="Client Detail" widgetVar="clientDialog" resizable="false" showEffect="explode" hideEffect="explode">
<h:panelGrid id="display" columns="2" cellpadding="4">
<f:facet name="header">
<h:outputText value="Selected Row" />
</f:facet>
<h:outputText value="ID" />
<h:outputText value="#{saClientcontroller.selectedSaClient.idSaClient}" />
<h:outputText value="NAME:" />
<h:outputText value="#{saClientcontroller.selectedSaClient.saClientName}" />
<h:outputText value="DESCRIPTION:" />
<h:outputText value="#{saClientcontroller.selectedSaClient.saClientAddress}" />
</h:panelGrid>
</p:dialog>
</f:view>
</h:body>
</html>
This is my Backing Bean.
public class SaClientController implements Serializable {
#EJB
private SaClientFacade saClientFacade;
private SaClient selectedSaClient;
private LazyDataModel<SaClient> lazyModel;
private List<SaClient> saclients;
/** Creates a new instance of SaClientController */
public SaClientController() {
}
#PostConstruct
public void Init() {
saclients = saClientFacade.Retrieve();
lazyModel = new LazyDataModelImp(saclients);
}
public LazyDataModel<SaClient> getLazyModel() {
return lazyModel;
}
public List<SaClient> getClients() {
return saClientFacade.Retrieve();
}
public SaClient getDetails() {
return selectedSaClient;
}
public String showDetails(SaClient selectedSaClient) {
this.selectedSaClient = selectedSaClient;
return "DETAILS";
}
public String update() {
System.out.println("###UPDATE###");
selectedSaClient = saClientFacade.Update(selectedSaClient);
return "SAVED";
}
public String list() {
System.out.println("###LIST###");
return "LIST";
}
public SaClient getSelectedSaClient() {
return selectedSaClient;
}
public void setSelectedSaClient(SaClient selectedSaClient) {
this.selectedSaClient = selectedSaClient;
}
public String dummyAction()
{
return null;
}
}
This is the LazyModelImp class
public class LazyDataModelImp extends LazyDataModel<SaClient> {
private List <SaClient> datasource;
public LazyDataModelImp(List<SaClient> datasource) {
this.datasource = datasource;
}
#Override
public SaClient getRowData(String rowKey) {
for (SaClient saclient : datasource) {
if (saclient.getIdSaClient().toString().equals(rowKey)) {
return saclient;
}
}
return null;
}
#Override
public Object getRowKey(SaClient saclient) {
return saclient.getIdSaClient().toString();
}
#Override
public List<SaClient> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) {
List<SaClient> data = new ArrayList<SaClient>();
//filter
for (SaClient saclient : datasource) {
boolean match = true;
for (Iterator<String> it = filters.keySet().iterator(); it.hasNext();) {
try {
String filterProperty = it.next();
String filterValue = filters.get(filterProperty);
String fieldValue = String.valueOf(saclient.getFilterSortFieldValue(filterProperty));
if (filterValue == null || fieldValue.startsWith(filterValue.toUpperCase()) || fieldValue.startsWith(filterValue.toLowerCase())) {
match = true;
} else {
match = false;
break;
}
} catch (Exception e) {
match = false;
}
}
if (match) {
data.add(saclient);
}
}
//rowCount
int dataSize = data.size();
this.setRowCount(dataSize);
//paginate
if (dataSize > pageSize) {
try {
return data.subList(first, first + pageSize);
} catch (IndexOutOfBoundsException e) {
return data.subList(first, first + (dataSize % pageSize));
}
}
else {
return data;
}
//sort
//if (sortField != null) {
// Collections.sort(data, new LazySorter(sortField, sortOrder));
//}
//return data;
}
}
I've already disabled the partial state saving in web.xml.
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
The backingBean is reinitialized the first time I click on the view detail commandButton in the last column of the dataTable in clienList.xhtml. And the dialog does not display at all. But after pressing F5. The dialog can be displayed but without any content, the only thing displayed in the dialog is the label outputText but not the bean values, they are empty. Sorry for newbie question. I will be extremely glad if anyone could advise what im doing is wrong, and maybe a little advise on the navigation and whether my strategy of displaying everything in index.xhtml (so I only have 1 view id all the time which is index.xhtml, right?) is right.
This may be the issue with your PrimeFaces dialog that you have an h:form surrounding the p:dialog. I have noticed the PrimeFaces dialog does not work properly when a child of a form element.
Try placing this dialog form inside of the contents of the dialog.
<p:dialog id="clientDialog" header="Client Detail" widgetVar="clientDialog" resizable="false" showEffect="explode" hideEffect="explode">
<h:form id="formdialog" prependId="false">
<h:panelGrid id="display" columns="2" cellpadding="4">
...
I have a JSF page which has a variable number inputText elements containing numeric weights. These are all bound to Weight objects in my backing bean. I'd like to create a single actionListener button which will re-distribute the weights across all the input texts.
I can call the method in the backing bean which distributes the values contained in the weight objects within the backing bean, but for some reason those updated values are not reflected in the InputText elements.
It is my assumption that the values are being put back in the UI elements before I update the values. Just shows my lack of understanding of the JSF lifecycle.
Can someone tell me how I could accomplish this?
Here is the relevant part of the xhtml file. For each child I reference the "newWeight" object key'd by the child object. The newWeight objects are created in the loadFamily method which is bound to the preRenderView event:
<!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:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:h="http://java.sun.com/jsf/html">
<ui:composition template="/templates/layout.xhtml">
<f:metadata>
<f:viewParam name="familyId" required="true"
requiredMessage="familyId is required"
value="#{weighFamilyBacking.familyId}"></f:viewParam>
<f:event type="preRenderView"
listener="#{weighFamilyBacking.loadFamily}" />
</f:metadata>
<ui:define name="title">Weigh Family</ui:define>
<ui:define name="content">
<h:form>
<h2>Previous Weights</h2>
<rich:dataTable value="#{weighFamilyBacking.allWeights}" var="weight"
id="table">
<rich:column>
<f:facet name="header">
<h:outputText value="Child" />
</f:facet>
<h:outputText
value="#{weight.child.firstName} #{weight.child.lastName}" />
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Weight" />
</f:facet>
<h:outputText value="#{weight.weight}" />
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Weigh Time" />
</f:facet>
<h:outputText value="#{weight.weighTime}" />
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Payout Time" />
</f:facet>
<h:outputText value="#{weight.payoutTime}" />
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value="Payout Status" />
</f:facet>
<h:outputText value="#{weight.status}" />
</rich:column>
</rich:dataTable>
<h2>New Weights</h2>
<h:panelGroup id="newWeights">
<ul>
<ui:repeat var="child" value="#{weighFamilyBacking.children}">
<li><h:panelGroup layout="block">
<h:outputText value="#{child.firstName}" />
<h:outputLabel value="Lbs" for="lbs">
<h:inputText size="3" id="lbs"
value="#{weighFamilyBacking.newWeights[child].lbs}" />
</h:outputLabel>
<h:outputLabel value="Oz" for="oz">
<h:inputText id="oz" size="3"
value="#{weighFamilyBacking.newWeights[child].oz}" />
</h:outputLabel>
</h:panelGroup></li>
</ui:repeat>
<h:outputLabel value="Donate Only" for="donate">
<h:selectBooleanCheckbox id="donate"
value="#{weighFamilyBacking.donateOnly}" />
</h:outputLabel>
</ul>
</h:panelGroup>
<h:commandButton
actionListener="#{weighFamilyBacking.distributeWeights}"
immediate="true" value="Redistribute" />
<h:commandButton action="cancel" value="Cancel" />
<h:commandButton action="#{weighFamilyBacking.save}" value="Save" />
</h:form>
</ui:define>
</ui:composition>
</html>
Here is the backing bean:
#ViewScoped
#ManagedBean
public class WeighFamilyBacking extends BaseForm implements Serializable {
private static final long serialVersionUID = 3710213437377609887L;
private Integer familyId;
private Boolean donateOnly;
public Boolean getDonateOnly() {
return donateOnly;
}
public void distributeWeights(ActionEvent event) {
Integer oz = 0;
Integer count = 0;
for (WebWeight ww : newWeights.values()) {
System.out.println(ww);
oz += ww.getLbs() * 16;
oz += ww.getOz();
ww.setLbs(123); // Set the values to something to simulate re-distribution for now.
ww.setOz(456);
count++;
}
donateOnly = true;
}
public void setDonateOnly(Boolean donateOnly) {
this.donateOnly = donateOnly;
}
private Family family;
private HashMap<Child, WebWeight> newWeights;
public HashMap<Child, WebWeight> getNewWeights() {
return newWeights;
}
public void setNewWeights(HashMap<Child, WebWeight> newWeights) {
this.newWeights = newWeights;
}
public WeighFamilyBacking() {
newWeights = new HashMap<Child, WebWeight>();
}
public List<Weight> getAllWeights() {
List<Weight> weights = new ArrayList<Weight>();
for (Child c : getFamily().getChildrenAsList()) {
for (Weight w : c.getWeightsAsList())
weights.add(w);
}
Collections.sort(weights, new Comparator<Weight>() {
#Override
public int compare(Weight arg0, Weight arg1) {
if (arg0.getWeighTime() == null)
return -1;
Integer date = arg0.getWeighTime().compareTo(
arg1.getWeighTime());
if (date == 0)
return arg0.getChild().getFirstName()
.compareTo(arg1.getChild().getFirstName());
return date;
}
});
return weights;
}
#PostConstruct
public void init() {
}
public void loadFamily() {
if (family == null) {
setFamily(hcbbService.findFamilyById(getFamilyId()));
for (Child c : family.getChildrenAsList()) {
WebWeight w = new WebWeight();
newWeights.put(c, w);
}
}
}
public void setFamilyId(Integer id) {
this.familyId = id;
}
public Integer getFamilyId() {
return this.familyId;
}
public Family getFamily() {
return family;
}
public void setFamily(Family f) {
this.family = f;
}
public List<Child> getChildren() {
List<Child> children = getFamily().getChildrenAsList();
Collections.sort(children);
return children;
}
public String cancel() {
return "cancel";
}
public String save() {
for (Child c : newWeights.keySet()) {
WebWeight ww = newWeights.get(c);
Weight w = new Weight();
w.setWeighTime(new Date());
Double weight = (ww.getLbs() * 16.0 + ww.getOz()) / 16.0;
w.setWeight(weight);
w.setStatus(WeightStatus.AWAITING_PAYOUT);
c.getWeights().add(w);
}
hcbbService.updateRegistration(family);
return "success";
}
}
The goal is to allow us to put weights in a single child and then have it evenly distribute the values across all "newWeight" objects. Right now I would expect that all my UI elements linked to the NewWeight objects would be zero after I click redistribute (since that method is getting called, and the values are being reset), but they aren't.
Additional Info
My adjustment of the WebWeight objects is happening at the INVOKE_APPLICATION phase as expected. The objects have the correct values before Render response.. but not in the rendered components?
From Log:
BEFORE INVOKE_APPLICATION 5
net.halo3.hcbb.registration.WebWeight#2f6cd09f
net.halo3.hcbb.registration.WebWeight#10f48f0c
net.halo3.hcbb.registration.WebWeight#27db6586
AFTER INVOKE_APPLICATION 5
BEFORE RENDER_RESPONSE 6
oz=456 lbs=123 object=net.halo3.hcbb.registration.WebWeight#2f6cd09f
oz=456 lbs=123 object=net.halo3.hcbb.registration.WebWeight#10f48f0c
oz=456 lbs=123 object=net.halo3.hcbb.registration.WebWeight#27db6586
AFTER RENDER_RESPONSE 6
More Info
Here is the dump from logs, where I log getLbs and getOz.. You can see that getLbs or getOz on the WebWeight object is not called during the Render phase?
- BEFORE INVOKE_APPLICATION 5
net.halo3.hcbb.registration.WebWeight#12d58dfe
net.halo3.hcbb.registration.WebWeight#12d58dfe getLbz: 0
net.halo3.hcbb.registration.WebWeight#12d58dfe getOz:0
net.halo3.hcbb.registration.WebWeight#25d285b
net.halo3.hcbb.registration.WebWeight#25d285b getLbz: 0
net.halo3.hcbb.registration.WebWeight#25d285b getOz:0
net.halo3.hcbb.registration.WebWeight#6c317dc9
net.halo3.hcbb.registration.WebWeight#6c317dc9 getLbz: 0
net.halo3.hcbb.registration.WebWeight#6c317dc9 getOz:0
- AFTER INVOKE_APPLICATION 5
- BEFORE RENDER_RESPONSE 6
- AFTER RENDER_RESPONSE 6
The thing is that you have set the immediate attribute on the command button.
This will cause your action listener to be called during the APPLY_REQUEST phase, but additionally UPDATE_MODEL will not be invoked and when the view is rendered again it will render the values that were still in the input components (components are stateful in JSF).
See this for some more elaborate information: JSF commandButton with immediate="true"
As you don't have any validators attached to your input components, the simplest solution in your case might be to remove the immediate attribute.
(offtopic, but I noticed your backing bean is rather randomly ordered which makes it a bit difficult to read. In Java/JSF you typically put the instance variables at the very beginning, then the constructor, post construct method, preRenderView event handler etc so the class reads as a story top to bottom)
It turned out that the problem was some of the xhtml. When I cleaned it all out and started simple it started working. I'm thinking maybe the outputLabels or the panelGroups.