PrimeFaces 3.0.M3 Cell Editor does not update value - jsf-2

I have read there, but i can't take edited value from primefaces datatable cellEditor, it gives me unedited value. i am using jpa.
xhtml page:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<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"
xmlns:p="http://primefaces.prime.com.tr/ui"
template="/templates/masterLayout.xhtml">
<ui:define name="windowTitle">
learn
</ui:define>
<ui:define name="content">
<h:form>
<p:dataTable value="#{lesson.lessonValue}" var="l" style="width: 400px">
<p:ajax event="rowEdit" listener="#{lesson.onEditRow}"/>
<p:column headerText="Lessons" style="width: 300px">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{l.lessonName}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{l.lessonName}" style="width: 100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Options">
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
</ui:define>
</ui:composition>
lesson.java:
public class lesson implements Serializable {
private String name;
protected EntityLesson[] lessonList;
public String getName() { return name; }
public void setName(String newValue) { name = newValue; }
EntityManagerFactory emf = Persistence.createEntityManagerFactory("DefaultPU");
public EntityLesson[] getLessonValue() {
EntityManager em = emf.createEntityManager();
List<EntityLesson> result;
try {
EntityTransaction entr = em.getTransaction();
boolean committed = false;
entr.begin();
try {
Query query = em.createQuery("SELECT l FROM EntityLesson l");
result = query.getResultList();
entr.commit();
committed = true;
lessonList = new EntityLesson[result.size()];
lessonList = result.toArray(lessonList);
} finally {
if (!committed) entr.rollback();
}
} finally {
em.close();
}
return lessonList;
}
public void onEditRow(RowEditEvent event) {
EntityLesson editedLesson = (EntityLesson)event.getObject();//gives me unedited value
............................
............................
}
EntityLesson.java:
#Entity
#Table(name="lessonaaa")
public class EntityLesson implements Serializable {
#Id
#Column(name="Lesson_Id", nullable=false)
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int lessonId;
#Column(name="Lessson", nullable=false, length=65)
private String lessonName;
public int getLessonId() { return lessonId; }
public void setLessonId(int lessonId) { this.lessonId = lessonId; }
public String getLessonName() { return lessonName; }
public void setLesson (String lessonName) { this.lessonName = lessonName; }
}

The problem occurs because of the JSF lifecycle:
When your dataTable is displayed it executes the JPQL to retrieve the list of lessons. After that they are displayed.
Now you edit on entity and hit save, the edited entity in the list has now the new value.
But what happens next, is that the list is fetched another time and then the listener method is executed with the newly fetched enitiy.
You can solve the problem if you store the list of entities in a local attribute in the view bean and fill it in the post construct method (annotated by #PostContruct) and you have to make the view bean #SessionScoped. Then use this list for the datatable.

My problem is similar:
The 'dataTable' contains as 'value' a list of entities:
<p:dataTable id="category" var="category" value="#{categoriesBacking.categoriesListEdit}">
If I select one for edit, the object which is passed to the event contains the previously unmodified value. I observed that this is due to the fact that dataTable's value is a list. As a work-around (to be able to use the component) I added a 'filterBy' to any of the 'column'. If the dataTable will contain only one value, that value will be interpreted correctly by the passed event in the managed bean.
!!! The event's object will be the modified instance.
I also use:
<p:ajax event="rowEdit" update="#this" listener="#{categoriesBacking.onEditRow}" />
instead of dataTable's 'rowEditListener'.
Again, this is just a workaround.

I have almost exactly the same code except instead of using the <p:ajax> tag I am instead using the rowEditListener attribute of dataTable. Try this instead:
<p:dataTable ... rowEditListener="#{lesson.onEditRow}" ... >
...

This kind of problems are generally related to your backing bean. Your "lesson" class needs #ManagedBean (javax.faces.bean.ManagedBean) annotation. Simply add
#ManagedBean (name="YourBeanName")
#ViewScoped
just before public class lesson implements Serializable { line in your lesson.java

Related

How to iterate a HashMap with primefaces selectable datatable

I have tried different solutions but none is working in my case. I want all the rows in this datatable to be selectable. The problem seems to be the <ui:repeatthat is probably overriding the objects...
My bean:
#ManagedBean
#ViewScoped
public class Chat {
private static Map<String, List<ChatObject>> chat = new LinkedHashMap<String, List<ChatObject>>();
private ChatObject selectedChatObject;
public void onChatRowSelection(){
if(getSelectedChatObject() != null){
System.out.println("test");
}
}
public List<Map.Entry<String, List<ChatObject>>> getChatList() {
Set<Map.Entry<String, List<ChatObject>>> productSet = chat.entrySet();
return new ArrayList<Map.Entry<String, List<ChatObject>>>(productSet);
}
#PostConstruct
public void postConstructMethod() {
if(chat.isEmpty()){
List<ChatObject> objectsList1 = new ArrayList<ChatObject>();
objectsList1.add(new ChatObject("3369818", "1", "1"));
objectsList1.add(new ChatObject("3369819", "2", "2"));
objectsList1.add(new ChatObject("3369820", "3", "3"));
chat.put("Chat Topic 1", objectsList1);
List<ChatObject> objectsList2 = new ArrayList<ChatObject>();
objectsList2.add(new ChatObject("3369813", "4", "4"));
objectsList2.add(new ChatObject("3369815", "5", "5"));
chat.put("Chat Topic 2", objectsList2);
}
}
public ChatObject getSelectedChatObject() {
return selectedChatObject;
}
public void setSelectedChatObject(ChatObject selectedChatObject) {
this.selectedChatObject = selectedChatObject;
}
}
My JSF:
<!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:p="http://primefaces.org/ui"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<h:form id="form" enctype="multipart/form-data" acceptcharset="ISO-8859-1">
<ui:repeat value="#{chat.chatList}" var="chatEntry">
<h2><h:outputText value="#{chatEntry.key}" /></h2>
<br />
<p:dataTable
value="#{chatEntry.value}"
var="chatEntryVar"
widgetVar="chatTableWV"
styleClass="geralBorderless"
style="cursor:pointer"
rowKey="#{chatEntryVar.id}"
rendered="true"
selectionMode="single"
selection="#{chat.selectedChatObject}"
paginatorAlwaysVisible="false">
<p:ajax event="rowSelect"
listener="#{chat.onChatRowSelection}"
oncomplete="chatTableWV.unselectAllRows();">
</p:ajax>
<p:column>
<h:outputText value="#{chatEntryVar.name}" />
</p:column>
</p:dataTable>
</ui:repeat>
</h:form>
</html>
All the 5 ChatObject in my Map are successfully shown in my page. But onChatRowSelection method will only print "test" when I click in the rows related to the second list I added to my map: objectList2. When I click in the lines from the first list I added objectList1, when the system enters in the onChatRowSelection method, selectedChatObject will be null. How can I fix this?
Your problem is here:
<ui:repeat ...>
<p:dataTable ... widgetVar="chatTableWV">
<p:ajax ... oncomplete="chatTableWV.unselectAllRows();">
Multiple data tables are been assigned exactly the same widgetVar name in JavaScript scope. In effects, the following JavaScript code is generated:
window['chatTableWV'] = new Widget(tableElement1);
window['chatTableWV'] = new Widget(tableElement2);
window['chatTableWV'] = new Widget(tableElement3);
// ...
Basically, every iteration overrides the last object assigned to the declared widgetVar name until it ends up referencing the last one. All widgets expect of the last one are basically unavailable, causing them to not be functional anymore as to row selection.
Fix it accordingly by giving them each an unique widgetVar. You could use the iteration index of <ui:repeat> for this.
<ui:repeat ... varStatus="loop">
<p:dataTable ... widgetVar="chatTableWV_#{loop.index}">
<p:ajax ... oncomplete="chatTableWV_#{loop.index}.unselectAllRows();">
This way the following JavaScript code is generated:
window['chatTableWV_0'] = new Widget(tableElement1);
window['chatTableWV_1'] = new Widget(tableElement2);
window['chatTableWV_2'] = new Widget(tableElement3);
// ...
And finally PrimeFaces widget manager can find them all.

JSF #ViewScoped Bean State is Lost

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

JSF2: pass object from list (dataGrid) to action method of commandButton

How can i pass an object to the action method of an commandButton? I use a datatable which is the basis of a composite component. The composite component should provide the possibility to exchange the buttons which are added to the rows of the datatable. I thought i can realize this with facets, but i have problems passing objects from the datatables list to action methods, neither directly via an EL nor via an property action listener.
View:
<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:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:customer="http://java.sun.com/jsf/composite/components/customer">
<ui:composition template="/WEB-INF/templates/template.xhtml">
<ui:define name="content">
<h:form id="customerList">
<customer:list list="#{customerControllerBean.list}">
<f:facet name="rowButton">
<h:commandButton value="#{msg.deleteButtonLabel}"
action="#{customerControllerBean.delete(customer)}" />
<h:commandButton value="#{msg.deleteButtonLabel}" action="#{customerControllerBean.deleteCustomer}">
<f:setPropertyActionListener target="#{customerControllerBean.customer}" value="#{customer}"/>
</h:commandButton>
<h:button outcome="customerdetail.jsf?id=#{customer.id}"
value="#{msg.editButtonLabel}" />
</f:facet>
</customer:list>
</h:form>
</ui:define>
</ui:composition>
</html>
Using the following composite component customer:list:
<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:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute name="list" />
<composite:facet name="rowButton" />
</composite:interface>
<composite:implementation>
<p:dataTable id="customer" var="customer" value="#{cc.attrs.list}">
...
<p:column>
<composite:renderFacet name="rowButton" />
</p:column>
</p:dataTable>
</composite:implementation>
</html>
The backing bean:
#Named
#ConversationScoped
public class CustomerControllerBean implements Serializable {
private static final long serialVersionUID = 6168621124401208753L;
List<Customer> allCustomers = null;
private Customer customer;
// setters and getters ...
#PostConstruct
public void loadAllCustomers() {
// load customers
}
public List<Customer> getList() {
return allCustomers;
}
public String delete(Customer customer) {
// delete customer...
return "deleted";
}
public String deleteCustomer() {
// delete customer...
return "deleted";
}
Is it not possible to pass objects to methods in this context?
Since you're using Primefaces you could take advantage of the its datatable features like its properties and events to set your model.
Using Primefaces' DataTable features
In your controller you may specify the model and the operations to be performed on it, in this case I used an EJB as example.
#ManagedBean
#ViewScoped
public class CustomerBean
{
private Customer model;
#EJB
private CustomerService cs;
public void rowSelected()
{
// log or do stuff
}
public void delete()
{
cs.delete(model);
}
// getters & setters
}
Then you specify the selectionMode and the selection properties in your datatable, with the selection being mapped to your model.
<p:dataTable id="dtModel" var="row" value="#{bean.list}" selectionMode="single" selection="#{bean.model}">
<p:ajax event="rowSelect" process="#this" listener="#{bean.rowSelected}" update=":content" />
</p:datatable>
In this case I used a listener in the p:ajax tag but it is only an example that may be useful if you want to do something with your model once it is selected, but it is not required to set your model. Your model will be set using the bean's setter method.
Passing row as parameter
In your controller you specify the method that receives the model as parameter.
#ManagedBean
#ViewScoped
public class CustomerBean
{
#EJB
private CustomerService cs;
public void delete(Customer candidate)
{
cs.delete(candidate);
}
// getters & setters
}
And in your datatable you use the row object as specified in var property.
<p:dataTable id="dtModel" var="row" value="#{bean.list}">
<p:column headerText="name">
<h:outputText value="#{row.name}" />
</p:column>
<p:column headerText="delete">
<p:commandButton value="delete" actionListener="#{bean.delete(row)}" />
</p:column>
</p:datatable>
I prefer to use the first example as it allows you to set the model by selecting a row and then performing various operations on it, like delete, edit or view its details. You could enable or disable buttons on your UI by checking if the model is selected or not, etc...
Hint
Instead of Composite Components you could use simple Facelets templates to create a simple taglib. They usually work fine, the only downside is that you cannot enforce an interface to the use of these components.
You may also check the PrimeFaces showcase, which has a lot of useful examples.
I hope it helps.

JSF El expression retaining old value (JSF life cycle)

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

Changes to backing object in actionListener not reflected in bound UI elements

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.

Resources