Primefaces Dataexporter and get method - jsf-2

With a simple class wich contains only a list of list of String, I can view all its elements in a p:dataTable with the get(int) method of class List but it fails when I try to export this with the p:dataExporter component.
Here's the Java source code :
#ManagedBean
#SessionScoped
public class MainClass {
private List<ArrayList<String>> listOfListOfString;
public List<ArrayList<String>> getListOfListOfString() {
return listOfListOfString;
}
public void setListOfListOfString(List<ArrayList<String>> listOfListOfString) {
this.listOfListOfString = listOfListOfString;
}
public MainClass() {
listOfListOfString = new ArrayList<ArrayList<String>>();
ArrayList<String> firstList = new ArrayList<String>();
firstList.add("a");
firstList.add("b");
listOfListOfString.add(firstList);
ArrayList<String> secondList = new ArrayList<String>();
secondList.add("1");
secondList.add("2");
listOfListOfString.add(secondList);
}
}
And the XTHML code :
<h:body>
Hello from Facelets
<h:form prependId="false">
<p:dataTable id="tbl" var="myList" value="#{mainClass.listOfListOfString}" paginator="true" rows="10" >
<p:column headerText="First column">
<h:outputText value="#{myList.get(0)}"/>
</p:column>
<p:column headerText="Second column">
<h:outputText value="#{myList.get(1)}"/>
</p:column>
</p:dataTable>
<h:commandLink value=" csv">
<p:dataExporter type="csv" target="tbl" fileName="userList" />
</h:commandLink>
</h:form>
</h:body>
And the error stack when I click on the csv link:
For input string: "get"
- Stack Trace
java.lang.NumberFormatException: For input string: "get"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:449)
at java.lang.Integer.parseInt(Integer.java:499)
at javax.el.ListELResolver.coerce(ListELResolver.java:173)
at javax.el.ListELResolver.getType(ListELResolver.java:72)
Do you have an idea why p:dataTable can use the get(int) method and p:dataExporter can't?
Thanks,
Philippe

Probably both components are implemented differently.
But you can access list elements this way:
#{myList[n]}
where n is the list index.

Related

Primefaces datatable hasn't been refreshed after applying the filter

I have some code is similar to the following showcase:
http://www.primefaces.org/showcase/ui/data/datatable/filter.xhtml
The filter is applied correctly in the backing bean, although the datatable hasn't been refreshed with the new filtered rows. It remains as it is before applying the filter. Is there something missing or wrong in this showcase?
<h:form>
<p:dataTable var="serviceEntity" value="#{serviceSearchMB.allServices}" widgetVar="serviceSearchTable"
emptyMessage="No services found with given criteria" filteredValue="#{serviceSearchMB.filteredServices}">
<f:facet name="header">
<h:outputText value="Search all fields:" />
<p:inputText id="globalFilter" onkeyup="PF('serviceSearchTable').filter();"
style="width:150px" placeholder="Enter keyword" />
</f:facet>
<p:column filterBy="#{serviceEntity.serviceName}" headerText="Service Name" filterMatchMode="contains" >
<h:outputText value="#{serviceEntity.serviceName}" />
</p:column>
...
Backing Bean:
#ManagedBean(name="serviceSearchMB")
#RequestScoped
public class ServiceSearchManagedBean implements Serializable {
private List<ServiceSearchEntity> filteredServices;
public List<ServiceSearchEntity> getFilteredServices() {
return filteredServices;
}
public void setFilteredServices(List<ServiceSearchEntity> filteredServices) {
this.filteredServices = filteredServices; // Already set the filtered list correctly.
}
public List<ServiceSearchEntity> getAllServices() {
//already returns all services.
}
...

Save and update on same xhtml is not working in primefaces

Hi i tried the following functionality using primefaces.
In my xhtml i have a input field which takes input and saves into db.After completion of save i display the saved data in data table of primefaces.
Upto now works fine.now i add single selection to datatable .when user click on the row i update the same input column with selected data.
For this i use the following code
<h:form id="form">
<p:growl id="messages" />
<p:panel id="panel" header="Currency">
<h:panelGrid columns="2" id="currencyGrid">
<p:outputLabel value="Currency :"/>
<p:inputText value="#{currencyBean.currencyMaster.currDesc}"/>
</h:panelGrid>
<p:commandButton value="Add" action="#{currencyBean.saveCurrency}"
update="currencytable">
</p:commandButton>
<p:dataTable id="currencytable" var="cur"
value="#{currencyBean.currencyList}" widgetVar="dlg"
selection="#{currencyBean.currencyMaster}"
selectionMode="single" rowKey="#{cur.currId}">
<p:ajax event="rowSelect" listener="#{currencyBean.onRowSelect}"
update=":form:currencyGrid" />
<p:column headerText="ID" style="font-size:12px;">
<h:outputText value="#{cur.currId}" />
</p:column>
<p:column headerText="Description" style="font-size:12px;">
<h:outputText value="#{cur.currDesc}" />
</p:column>
</p:dataTable>
</h:form>
And My Bean code is:
#managedBean
#viewScoped
#component
public class CurrencyBean implements Serializable{
private static final long serialVersionUID = 1L;
#Autowired
private CurrencyMaster currencyMaster;
private List<CurrencyMaster> currencyList;
public CurrencyMaster getCurrencyMaster() {
return currencyMaster;
}
public void setCurrencyMaster(CurrencyMaster currencyMaster) {
this.currencyMaster = currencyMaster;
}
public void saveCurrency(){
try{
currencyService.saveCurrency(currencyMaster);
}catch(Exception e){
e.printStackTrace();
}
}
#PostConstruct
public void currencyList(){
setCurrencyList(currencyService.getCurrencyList());
}
public void onRowSelect(SelectEvent event) {}
public void onRowUnselect(UnselectEvent event) {}
}
So when i click on currrencytable row the input field populated properly and update operation also.
The problem is when i directly enter the data into input column my globalMaster property is going to be null.
And the following error is occured;
attempt to create saveOrUpdate event with null entity
I change the scopes of the bean but i did not find the solution.
And i find more solutions for the above exception but my problem is the new values are does not set to currencymaster.
Is there any mistake i done in this context.please guide me..

f:setPropertyActionListener doesn't call setter on backed bean

I cant't understand why in my PrimeFaces view when I call
<f:setPropertyActionListener value="#{item}" target="#{tagController.current}" />
it never calls the backed bean tagController.setCurrent method.
I've the following view:
<h:form id="tableForm" styleClass="form-horizontal">
<h:panelGroup id="dataPanel">
<p:dataTable value="#{tagController.lazyModel}"
lazy="true"
id="table"
var="item"
paginator="true"
rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="10,20,50" >
<p:column headerText="Name" sortBy="#{item.name}" filterBy="#{item.name}">
<h:outputText value="#{item.name}"/>
</p:column>
<p:column>
<p:commandLink id="testButton" update=":testForm:panel" process="#this">
<h:outputText value="Test" />
<f:setPropertyActionListener value="#{item}" target="#{tagController.current}" />
</p:commandLink >
</p:column>
</p:dataTable>
</h:panelGroup>
</h:form>
<br/>
<h:form id="testForm" styleClass="form-horizontal">
<p:panelGrid columns="4" id="panel" >
<h:outputLabel value="Name: #{tagController.current.name}" />
</p:panelGrid>
</h:form>
and the following backed bean:
#ViewScoped
#Named
public class TagController implements Serializable {
#Inject
TagFacade tagFacade;
protected LazyDataModel<Tag> lazyModel;
protected ResourceBundle bundle = ResourceBundle.getBundle("resources/messages");
#Getter
protected Tag current = new Tag();
public void setCurrent(Tag current) {
System.out.println(">>>>>>>>>> THIS METHOD IS NEVER CALLED ? WHY ?");
this.current = current;
}
public LazyDataModel<Tag> getLazyModel() {
//... omitted for brevity
}
}
The datatable is working well, I see data, the paginator, filters and sorting works well but when I click the test link nothing happens (no exceptions, no javascript errors into the html page, no message print into stdout...).
I'm using Glassfish 3.1.2 / Mojarra 2.1.22 / PrimeFaces 3.5.
Someone can help me ?
Many thanks in advance...
I notice that you are mixing CDI with JSF annotations. there is no view scoped annotations for CDI.you should replace view scoped with a CDI Scope or change #named annotations to #Managedbean
<p:column>
<p:commandButton id="bb" actionListener="#{yourmanagedbean.setmyvalue(item)}"
title="Test" update=":testForm:panel">
</p:commandButton>
</p:column>
In backing bean look like this
public void setCurrent(Tag current) throws Exception {
try {
this.current = current;
} catch (Exception e) {
// ...
}
}
Try to make panelgrid inside a panel and update it.
Since you are using annotation for getter, I suspect that by default the setter will pass directly by your variable.
You should try like this
private Tag current = new Tag();
public void setCurrent(Tag current) {
System.out.println(">>>>>>>>>> THIS METHOD IS NEVER CALLED ? WHY ?");
this.current = current;
}
public Tag getCurrent() {
return this.current;
}
More info :
Lombok Getter setter
I had the same problem but with a different solution. I had the annotations correct and so on, but had a dialog (I didn't even use) that had the following code
<h:inputText value="#{aSBean.newElement.vaSl}" validatorMessage="Nr bitte numerisch eingeben">
<f:validateDoubleRange minimum="1" maximum="999" />
</h:inputText>
Somehow (still don't know why) my setter doesn't work with this piece of code in the dialog. Just adding this in case others have this problem, because it took me days to find out.

Custom scope of a ManagedBean in JSF2.0 with PrimeFaces 3.5

Following is my requirement-
Here I have a p:panelGrid which can add & delete the row of table. The grid contains some p:inputText and various other PrimeFaces components along with a p:fileUpload component in each row. The component p:fileUpload is set with mode="advanced" auto="true" attributes, which automatically uploads the file and hide itself after completing the successful upload.
The whole p:panelGrid is in #ViewScoped, hence working fine. I kept p:fileUpload component in #RequestScoped since for each upload request it has to upload the file but after adding new row, the previous state is not persisted anymore. so the p:fileUpload is starting visible in previous rows also. That's what I don't want. Do I need to write any custom scope for it?
Below is the view-|
<h:form>
<p:panel id="agentForm" header="#{msg.AGENTS_INFORMATION}"
style="overflow:auto; margin-bottom: 2px">
<div align="center" style="margin-top: 20px; margin-bottom: 2px">
<ui:repeat value="#{agent.scenarioList}" var="c">
<p:panelGrid>
<p:row>
<p:column>
<p:inputText id="ipaddress" value="#{c.machineIpAddress}"
style="width:90%">
<p:watermark for="ipaddress" value="#{msg.MACHINE_IP_ADDRESS}" />
</p:inputText>
</p:column>
<p:column>
<p:inputText id="username" value="#{c.machineUsername}"
style="width:90%">
<p:watermark for="username" value="#{msg.MACHINE_USERNAME}" />
</p:inputText>
</p:column>
<p:column>
<p:password id="passwd" value="#{c.machinePassword}">
<p:watermark for="passwd" value="#{msg.MACHINE_PASSWORD}" />
</p:password>
</p:column>
<p:column id="fileUpload">
<p:fileUpload rendered="#{!fileUploadController.hidden}"
label="Upload Script" style="font-size: 100% !important;"
showButtons="false"
fileUploadListener="#{fileUploadController.upload}"
mode="advanced" auto="true" sizeLimit="100000"
allowTypes="/(\.|\/)(py|txt)$/"
update="fileUpload, outPanel, :message" />
<p:outputPanel id="outPanel">
<!-- Below outputLabel will be linked to uploaded file, so that User can see the file -->
<p:outputLabel style="cursor: pointer" value="View uploded Script"
label="View Script" rendered="#{fileUploadController.hidden}" />
</p:outputPanel>
</p:column>
<p:column>
<p:inputText id="testname" value="#{c.testName}"
style="width:90%">
<p:watermark for="testname" value="#{msg.TEST_NAME}" />
</p:inputText>
</p:column>
<p:column>
<p:spinner id="threads" value="#{c.threads}" min="1" max="500"
size="8">
<p:tooltip for="threads" value="#{msg.TEST_NAME}"
showEffect="slide" hideEffect="slide" />
</p:spinner>
</p:column>
<p:column>
<p:selectBooleanCheckbox id="chkSelected" value="#{c.selected}">
<p:tooltip for="chkSelected" value="#{msg.CHECKBOX}"
showEffect="slide" hideEffect="slide" />
</p:selectBooleanCheckbox>
</p:column>
</p:row>
</p:panelGrid>
</ui:repeat>
<p:toolbar style="margin-top: 10px;">
<p:toolbarGroup align="right">
<p:commandButton value="#{msg.ADD_IT}"
update=":message, agentForm"
actionListener="#{agent.addComponent()}" />
<p:commandButton value="#{msg.DELETE_IT}"
update=":message, agentForm"
actionListener="#{agent.deleteComponent()}" />
</p:toolbarGroup>
</p:toolbar>
</div>
</p:panel>
</h:form>
My managed bean which is in #ViewScoped look like this-
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import org.ravij.performance.model.Scenario;
#ManagedBean(name = "agent")
#ViewScoped
public class AgentInfo implements Serializable {
private static final long serialVersionUID = 1L;
List<Scenario> scenarioList;
#PostConstruct
public void initBean() {
this.scenarioList = new ArrayList<Scenario>();
this.scenarioList.add(new Scenario());
}
public void addComponent() {
if (this.scenarioList != null) {
this.scenarioList.add(new Scenario());
} else {
this.initBean();
}
}
public void deleteComponent() {
List<Scenario> itemsToDelete = new ArrayList<Scenario>();
if (this.scenarioList != null) {
for (Scenario b : this.scenarioList) {
if (b.isSelected()) {
itemsToDelete.add(b);
}
}
this.scenarioList.removeAll(itemsToDelete);
}
}
public List<Scenario> getScenarioList() {
return scenarioList;
}
public void setScenarioList(List<Scenario> scenarioList) {
this.scenarioList = scenarioList;
}
}
The Scenario object contains all the information of a row. Below is the code-
package org.ravij.performance.model;
import java.io.Serializable;
public class Scenario implements Serializable {
private String machineIpAddress;
private String machineUsername;
private String machinePassword;
private String uploadedFilePath;
private String testName;
private int threads = 1;
private boolean selected = false;
//Below are the getters and setter w.r.t all the above variables
//I am not putting it, to make the code short
}
The managed bean FileUploadController is in #RequestScoped
You should simply keep your hidden attribute with the other values in your #ViewScoped bean. Your current code has a single hidden attribute shared with all your <p:fileUpload components which is probably not what you want.
The behavior looks good because you are only updating the current fileUpload but according to your code all the others <p:fileUpload component are supposed to be hidden.
You should also put your <h:form into your <ui:repeat so that you can know the current line which is concerned by the file being uploaded by putting something like an index (which you can get from the <ui:repeat using varStatus attribute) or any other identifier to match the current line in an hidden input.
From #{fileUploadController.upload} the easiest manner to get the hidden parameter is to get the response from FacesContext as explained here : How to get parametrs to BackingBean from jsf page in <ui:repeat>
UPDATE
It was a bit harder than expected, the problem is that <p:fileUpload will send everything in the enclosing form (didn't try to play with process attribute) and thus it will be hard to know what row is concerned by the file upload.
Also I didn't knew that you couldn't put <h:form in your <ui:repeat but the behavior of your delete button is blocking as it expects to get everything in one form.
I made a working POC using dialog to put the fileupload outside, here is how :
The trivial Scenario.java :
public class Scenario implements Serializable {
private String machineIpAddress;
private String machineUsername;
private String machinePassword;
private String uploadedFilePath;
private String testName;
private int threads = 1;
private boolean selected = false;
private boolean hidden = false; // This is new
// + Getters/Setters
}
A few changes in the AgentInfo.java :
#ManagedBean(name = "agent")
#ViewScoped
public class AgentInfo implements Serializable {
private List<Scenario> scenarioList;
private Scenario currentScenario; // This is new
// I removed the #PostConstruct which I rarely use
public void addComponent() {
if (this.scenarioList != null) {
this.scenarioList.add(new Scenario());
}
}
public void deleteComponent() {
if (this.scenarioList == null) {
return;
}
List<Scenario> itemsToDelete = new ArrayList<Scenario>();
for (Scenario scenario : this.scenarioList) {
if (scenario.isSelected()) {
itemsToDelete.add(scenario);
}
}
this.scenarioList.removeAll(itemsToDelete);
}
// This is new, it must be called before opening the upload dialog
// in order to keep a pointer on the current scenario you are working on
public void prepareUpload(Scenario scenario) {
this.currentScenario = scenario;
}
// I put the upload method here
public void upload(FileUploadEvent event) {
// Do what you need to do here
this.currentScenario.setHidden(true);
RequestContext.getCurrentInstance().execute("uploadDialogWidget.hide()");
}
public List<Scenario> getScenarioList() {
if (this.scenarioList == null) {
this.scenarioList = new ArrayList<Scenario>();
this.scenarioList.add(new Scenario());
}
return scenarioList;
}
public void setScenarioList(List<Scenario> scenarioList) {
this.scenarioList = scenarioList;
}
public Scenario getCurrentScenario() {
return currentScenario;
}
public void setCurrentScenario(Scenario currentScenario) {
this.currentScenario = currentScenario;
}
}
The most changes are in the view, I put a <h:commandButton to open the dialog in the form. I also added the dialog, and added the redisplay attribute for your password fields (which is necessary to have if you want to keep the value after form submission).
Note that I removed references to a component with message id which was not gave, don't forget to reintroduce it.
the .xhtml :
<h:form id="agentForm">
<p:panel header="#{msg.AGENTS_INFORMATION}"
style="overflow:auto; margin-bottom: 2px">
<div align="center" style="margin-top: 20px; margin-bottom: 2px">
<ui:repeat value="#{agent.scenarioList}" var="c">
<p:panelGrid>
<p:row>
<p:column>
<p:inputText id="ipaddress" value="#{c.machineIpAddress}"
style="width:90%">
<p:watermark for="ipaddress" value="#{msg.MACHINE_IP_ADDRESS}" />
</p:inputText>
</p:column>
<p:column>
<p:inputText id="username" value="#{c.machineUsername}"
style="width:90%">
<p:watermark for="username" value="#{msg.MACHINE_USERNAME}" />
</p:inputText>
</p:column>
<p:column>
<p:password id="passwd" value="#{c.machinePassword}" redisplay="true">
<p:watermark for="passwd" value="#{msg.MACHINE_PASSWORD}" />
</p:password>
</p:column>
<p:column id="fileUpload">
<p:commandButton icon="ui-icon-arrowthick-1-n" value="Upload"
actionListener="#{agent.prepareUpload(c)}"
update=":uploadDialog"
oncomplete="uploadDialogWidget.show()"
rendered="#{!c.hidden}" />
<p:outputPanel id="outPanel">
<!-- Below outputLabel will be linked to uploaded file, so that User can see the file -->
<p:outputLabel style="cursor: pointer" value="View uploded Script"
rendered="#{c.hidden}" />
</p:outputPanel>
</p:column>
<p:column>
<p:inputText id="testname" value="#{c.testName}"
style="width:90%">
<p:watermark for="testname" value="#{msg.TEST_NAME}" />
</p:inputText>
</p:column>
<p:column>
<p:spinner id="threads" value="#{c.threads}" min="1" max="500"
size="8">
<p:tooltip for="threads" value="#{msg.TEST_NAME}"
showEffect="slide" hideEffect="slide" />
</p:spinner>
</p:column>
<p:column>
<p:selectBooleanCheckbox id="chkSelected" value="#{c.selected}">
<p:tooltip for="chkSelected" value="#{msg.CHECKBOX}"
showEffect="slide" hideEffect="slide" />
</p:selectBooleanCheckbox>
</p:column>
</p:row>
</p:panelGrid>
</ui:repeat>
<p:toolbar style="margin-top: 10px;">
<p:toolbarGroup align="right">
<p:commandButton value="#{msg.ADD_IT}" update="agentForm"
actionListener="#{agent.addComponent()}" />
<p:commandButton value="#{msg.DELETE_IT}" update="agentForm"
actionListener="#{agent.deleteComponent()}" />
</p:toolbarGroup>
</p:toolbar>
</div>
</p:panel>
</h:form>
<p:dialog id="uploadDialog" widgetVar="uploadDialogWidget" header="File upload">
<h:form rendered="#{!empty agent.currentScenario}">
<p:fileUpload
label="Upload Script" style="font-size: 100% !important;"
showButtons="false"
fileUploadListener="#{agent.upload}"
mode="advanced" auto="true" sizeLimit="100000"
allowTypes="/(\.|\/)(py|txt)$/"
update=":agentForm">
</p:fileUpload>
<p:commandButton value="Cancel" onclick="uploadDialogWidget.hide();" onstart="return false;" />
</h:form>
</p:dialog>
You should consider to move from <p:panelGrid to a <p:dataTable which has a built in mechanism to work with row selection.

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

Resources