JSF 2. Strange behavior navigating between pages using IE7 - jsf-2

I have a web application where the first page is a login page, and once I am logged correctly, the main page is displayed. The page has a tabbed menu and if the first time I click on one of the tabs, the main page is refreshed again instead of going to the requested page. This occurs only on the first clic. The other times, everything works fine.
I texted it with Firefox, Chrome and IE7, and this behavior only happened with IE7. Why could this be? Where the error could be? Because I don't know what piece of my code should I copy here to clarify my question.
PD: I use a Filter and the main page uses a bean to populate a table. I also tried <redirect/> tag in faces-cofig.xml, and it solved the problem. But the page always showed the "Invalid User" popup contained in the login page. And finally, I discarded it.
Update with some code
I think the problem isn't in the main page, because I replaced it by other pages and the behavior is the same... (Update 2) But with a simple html page it works fine.
login.xhtml:
<h:form id="login">
<h:outputText value="#{msg['login.user']}"/>
<h:inputText value="#{LogBean.name}" required="true"/>
<h:outputText value="#{msg['login.password']}"/>
<h:inputSecret value="#{LogBean.pass}" required="true"/>
<p:commandButton id="botonAccesoPrim"
value="#{msg['login.enter']}"
action="#{LogBean.checkLog}"
oncomplete="dlg1.show();">
</p:commandButton>
<p:dialog id="popup"
visible="#{LogBean.popup}"
widgetVar="dlg1"
modal="true">
<h:outputText value="Invalid User." />
</p:dialog>
LogBean:
public class LogBean {
private String name;
private String pass;
private String validate = "";
private String popup = "false";
//Getters, setters
public String checkLog() throws Exception {
if (correctLog(md5Final)) {
popup = "false";
validate= "success";
return validate;
}
else {
popup = "true";
validate = "fail";
return validate;
}
}
public boolean correctLog(String md5) throws SQLException {
boolean correct = false;
String sql = "SELECT ...";
String passBBDD = null;
cConexionOracle.conecta();
ResultSet result = OracleConnection.query(sql);
if (!(result.next()))
return correct;
else {
passBBDD = result.getString("pass");
if (md5.equals(passBBDD))
correct = true;
}
OracleConnection.desconect();
return correct;
}
public boolean isLogged () {
return name != null;
}
faces-config:
<managed-bean>
<managed-bean-name>LogBean</managed-bean-name>
<managed-bean-class>LogBeanClass</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>mainBean</managed-bean-name>
<managed-bean-class>MainBeanClass</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/HTML/login.xhtml</from-view-id>
<navigation-case>
<from-action>#{LogBean.checkLog}</from-action>
<from-outcome>success</from-outcome>
<to-view-id>/HTML/main.xhtml</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-action>#{LogBean.checkLog}</from-action>
<from-outcome>fail</from-outcome>
<to-view-id>/HTML/login.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
FilterLogin:
public void doFilter (ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (req.getRequestURI().endsWith("login.jsf")) {
chain.doFilter(req, resp);
return;
}
HttpSession session = req.getSession(false);
if (session != null) {
LogBean BeanConnection = (LogBean) req.getSession().getAttribute("LogBean");
if (BeanConnection != null && BeanConnection.isLogged()) {
chain.doFilter(req, resp);
return;
}
}
resp.sendRedirect(req.getContextPath() + "/HTML/login.jsf");
}
web.xml
<filter>
<filter-name>Filter</filter-name>
<filter-class>FilterLogin</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter</filter-name>
<url-pattern>/HTML/*</url-pattern>
</filter-mapping>
mainBean: (Update 2)
private ArrayList<mainClass> mainList = new ArrayList<mainClass>();
private String name;
//...
//Getters, setters.
#PostConstruct
public void populateMainList() {
String sql = null;
if (name == null) {
sql = "SELECT ...";
}
else
sql = "SELECT ... LIKE '%"+name+"%'";
OracleConnection.connect();
ResultSet result = OracleConnection.query(sql);
try {
while(result.next()){
mainClass main = new mainClass();
main.set...(result.getLong("someProperty"));
mainList.add(main);
}
} catch (SQLException e) {
e.printStackTrace();
}
OracleConnection.disconnect();
}
public ArrayList<mainClass> getMainList() throws SQLException {
return mainList;
}
main.xhtml
<h:inputText id="search" value="#{mainBean.name}"> </h:inputText>
<h:commandButton id ="SubmitSearch" action="#{mainBean.seachButton}"></h:commandButton>
<h:commandButton id ="new" value="New" action="#{sistemaBean.newButton}"> </h:commandButton>
<t:dataTable id="data" rows="1" value="#{mainBean.mainList}" var="item"
width="95%" border="0" align="center" cellpadding="0" cellspacing="0">
<t:column width="42%">
<f:facet name="header">
<h:outputText value="Name"/>
</f:facet>
<h:commandLink value="#{item.shortName}" action="#{detailledMainBean.mainDetail}">
<f:param name="idMain" value="#{item.idMain}"/>
</h:commandLink>
</t:column>
<t:column>
<f:facet name="header">
<h:outputText value="Description"/>
</f:facet>
<h:outputText value="#{item.description}"/>
</t:column>
</t:dataTable>
<t:dataScroller id="scroller" for="data"
paginator="false" paginatorMaxPages="5"
paginatorColumnClass="style"
immediate="true"
pageCountVar="pageCount" pageIndexVar="pageIndex"
disableFacetLinksIfFirstPage="true"
disableFacetLinksIfLastPage="true"
renderFacetLinksIfFirstPage="false"
renderFacetLinksIfLastPage="false"
paginatorRenderLinkForActive="false"
renderFacetsIfSinglePage="false"
displayedRowsCountVar="true">
<f:facet name="previous">
<t:outputText styleClass="style" value=" « Previous | "/>
<t:outputText styleClass="style" value="Page #{pageIndex} / #{pageCount}"/>
</f:facet>
<f:facet name="next">
<t:outputText styleClass="style" value=" | Next »"/>
</f:facet>
</t:dataScroller>
Thanks in advance.

IE7 and jsf 2 will give you various problems. We have not encountered this problem specifically but many others.
Our problems mostly boiled down to tables. JSF is pretty table centric and many components translates to html with one or several tables. For example we commonly had to use some extra css for aligns.
For some tables we had to set the table header width with javascript. Problem was IE7 broke the table because it couldn't determine header width.
Unsure if you can draw any clues from this. But I would advise you to think in terms of workarounds rather than "what's wrong with the code".

Related

How to use j_security_check jsf

I want to use j_security_check authentication in order to validate the user credentials.
Basically what I am trying to achieve is when the user press submit then in case he is using wrong credentials then a message (p:growl) will show and if it’s successful then the dialog will closed.
There are many examples in the web but unfortunately I still can’t understand how to complete this puzzle :(
In my project I am using primefaces 4.0 & weblogic 10.3.2.0 (JAVA EE 5).
some code example:
<p:dialog id="dialog" widgetVar="dlg" resizable="false">
<h:form id="fLogin" prependId="false"
onsubmit="document.getElementById('fLogin').action = 'j_security_check';">
<h:panelGrid columns="2" cellpadding="5">
<h:outputLabel for="j_username" value="Username:" />
<p:inputText value="#{expBean.username}"
id="j_username" label="username"/>
<h:outputLabel for="j_password" value="Password:" />
<h:inputSecret value="#{expBean.password}"
id="j_password" label="password"/>
<p:commandButton id="submitButton"
value="Submit"
actionListener="#{expBean.run}" />
</h:panelGrid>
</h:form>
</p:dialog>
web.xml
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>main</web-resource-name>
<description/>
<url-pattern>main.jsf</url-pattern>
<http-method>POST</http-method>
</web-resource-collection>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>my-realm</realm-name>
</login-config>
<security-role>
<description/>
<role-name>MyRole</role-name>
</security-role>
exeBean:
public void run() {
FacesContext facesContext = FacesContext.getCurrentInstance();
}
Any guidelines and useful example will be much appreciated
Thanks
You were submitting the form by PrimeFaces ajax. That's why it fails. The j_security_check handler doesn't understand incoming JSF/PrimeFaces-flavored ajax requests and can't handle them appropriately by returning the desired XML response. It has to be a regular (synchronous) submit.
Turn off the ajax thing:
<p:commandButton ... ajax="false" />
By the way, your form declaration is clumsy. Just use <form> instead of <h:form>.
<form id="fLogin" action="j_security_check">
after experimenting some strategy, i choose not to use j_security_check and implement auth this way:
#ManagedBean
#ViewScoped
public class AuthBean implements Serializable
{
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(AuthBean.class);
#EJB
private PersistenceService service;
#ManagedProperty("#{user}")
private UserBean userBean;
private String email;
private String password;
private String originalURL;
#PostConstruct
public void init()
{
logger.debug("called");
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
if(originalURL == null)
{
originalURL = externalContext.getRequestContextPath();
}
else
{
String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING);
if(originalQuery != null)
{
originalURL += "?" + originalQuery;
}
}
logger.debug("originalURL: {}", originalURL);
}
public void login() throws IOException
{
logger.debug("called");
logger.debug("originalURL: {}", originalURL);
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
try
{
request.login(email, password);
}
catch(ServletException e)
{
JsfUtils.addErrorMessage(e, "authentication failed");
return;
}
Person person = service.queryOne(Person.class, "SELECT x FROM Person x WHERE x.email = ?1", email);
if(person == null)
{
JsfUtils.addErrorMessage("authorization failed");
return;
}
userBean.setPerson(person);
externalContext.redirect(originalURL);
}
public void logout() throws IOException
{
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.invalidateSession();
externalContext.redirect(externalContext.getRequestContextPath());
}
// getters/setters
}
using this form inside /login.xhtml:
<h:form>
<p:panel header="#{bundle.login}">
<h:panelGrid columns="3">
<h:outputLabel for="email" value="#{bundle.email}" />
<h:outputLabel for="password" value="#{bundle.password}" />
<h:panelGroup />
<p:inputText id="email" value="#{authBean.email}" label="#{bundle.email}" size="32" />
<p:password id="password" value="#{authBean.password}" label="#{bundle.password}" feedback="false" size="32" />
<p:commandButton value="#{bundle.login}" action="#{authBean.login}" icon="ui-icon ui-icon-check" />
</h:panelGrid>
</p:panel>
</h:form>
and this login-config:
<login-config>
<auth-method>FORM</auth-method>
<realm-name>some-realm-name</realm-name>
<form-login-config>
<form-login-page>/login.jsf</form-login-page>
<form-error-page>/login.jsf</form-error-page>
</form-login-config>
</login-config>

operations on validated text fields in jsf

I'm Using Primefaces 3.5. I have around 10 input text fields in my .xhtml page.Few text fields are made mandatory with attribute required="true".
I have a search button that displays Data from Database in a Data Table.The functionality of my page is to insert the values into these fields by on row select() the data in the Data Table of Search Button.
The Problem here is the data is inserting into the Fields which are highlighted with the red border ie fields with validations applied.
Example:
Transport Field has no validation but it had value that has to be inserted. These type of things are happening to many of my Input Fields.
Please give me some suggestions.
.xhtml file is:
<p:inputText id="email" value="#{addcust.c.email}" required="true"
validatorMessage="Enter Valid Email">
<f:validateRegex pattern="^[_A-Za-z0-9-\+]+(\.[_A-Za-z0-9-]+)*#[A-Za-z0-9-]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$"/></p:inputText>
<h:outputLabel value="Transport"></h:outputLabel>
<p:inputText value="#{addcust.c.transport}" </p:inputText>
<p:commandButton value="add" type="submit" update=":form,:msg" actionListener="#{addcust.onAddSelect}"</p:commandButton>
<p:commandButton value="Search" type="submit" onclick="ser.show() "></p:commandButton>
<p:dialog id="dialog11" header=" Search" widgetVar="ser" resizable="false" showEffect="fade"
hideEffect="explode" >
<p:dataTable id="dt" var="sd" value="#{addcust.al}" selection="#{addcust.c}">
<p:ajax event="rowSelect" update=":form" listener="#{addcust.onRowSelect}"
oncomplete="ser.hide()"/>
<p:column>
<f:facet name="header">
<h:outputText value="Email"/>
</f:facet>
<h:outputText value="#{sd.email}"/>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Transport"/>
</f:facet>
<h:outputText value="#{sd.transport}"/>
</p:column>
</p:dataTable>
customerbean.java
public class customerbean {
private String email;
private String transport;
public String getTransport() {
return transport;
}
public void setTransport(String transport) {
this.transport = transport;
}
return email;
}
public void setEmail(String email) {
this.email = email;
}
addcust.java
public customerbean c = new customerbean();
public ArrayList<customerbean> al;
public void onAddSelect(){
// Inserted my values into customer table.
}
public void onSearchSelect() {
try {
st = con.createStatement();
ResultSet rs = st.executeQuery("select * from customer where cmpid=" + getCurrcompanyid() + "");
al = new ArrayList<customerbean>();
while (rs.next()) {
customerbean s = new customerbean();
s.setEmail(rs.getString(1));
s.setTransport(rs.getString(2));
}
} catch (Exception e) {
System.out.println(e);
}
}
public void onRowSelect(SelectEvent event) throws SQLException {
customerbean r = (customerbean)event.getObject();
c = r;
}
If I'm not clear enough please leave me a comment .Thanks for Reading.

p:ajax event="sort" of p:dataTable does not process

For some strange reason I can't manage to process my data when I'm using <p:ajax event="sort" inside <p:dataTable , while it works just fine for <p:ajax event="page" and <p:ajax event="filter"
I'm using myfaces 2.0.11 with primefaces 3.4 (tried with 4.0 snapshot)
If I edit my cell input and do PAGINATE I do see the updated value of the cell in the listener method
If i edit my cell input and do SORT I do NOT see the updated value of the cell in the listener method, Any Idea why? I mean both p:ajax (sort/page) got the process="#form" so why its does not process? I inspected the network of the chrome dev tools and in both cases (sort/page) the relevant updated values are being sent to the server, but for some reason in the sort listener the values are not updated ,
b.t.w the only suspicious difference between page and sort ajax request is the following parameter that is present only in the sort request is:
my_table_skipChildren:true , what does it mean? skip from processing ?
I can grab the relevant ids+value from the request from the ExternalContext, but it will be last resort only
Here is a really simple example
Session Scoped Bean code:
#ManagedBean
#SessionScoped
public class myBean {
private List<MyObject> myList = new ArrayList<MyObject>();
#PostConstruct
public void init() {
myList.add(new MyObject("1", "2"));
myList.add(new MyObject("11", "22"));
myList.add(new MyObject("111", "222"));
myList.add(new MyObject("1a", "2a"));
myList.add(new MyObject("11a", "22a"));
myList.add(new MyObject("111a", "222a"));
}
public List<MyObject> getMyList() {
return myList;
}
public void setMyList(List<MyObject> myList) {
this.myList = myList;
}
}
MyObject code
public class MyObject {
private String one;
private String two;
public MyObject(String one, String two) {
super();
this.one = one;
this.two = two;
}
public String getOne() {
return one;
}
public void setOne(String one) {
this.one = one;
}
public String getTwo() {
return two;
}
public void setTwo(String two) {
this.two = two;
}
}
XHTML :
<p:dataTable id="my_table" value="#{myBean.myList}"
var="deviceRow" widgetVar="myTable"
paginator="true" rows="4" paginatorPosition="bottom"
paginatorTemplate="{FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}">
<p:ajax process="#form" event="sort" listener="#{myBean.detectSortEvent}"></p:ajax>
<p:ajax process="#form" event="page" listener="#{myBean.detectPageEvent}"></p:ajax>
<p:column id="table_selection_column_one" sortBy="#{deviceRow.one}" filterBy="#{deviceRow.one}">
<f:facet name="header">
<h:outputText value="Column One" />
</f:facet>
<h:inputText id="myRow_One" value="#{deviceRow.one}" />
</p:column>
<p:column id="table_selection_column_two" sortBy="#{deviceRow.two}" filterBy="#{deviceRow.two}">
<f:facet name="header">
<h:outputText value="Column Two" />
</f:facet>
<h:inputText id="myRow_Two" value="#{deviceRow.two}" />
</p:column>
</p:dataTable>
(I also asked it on primefaces forum but got no response)
Tried Andy workaround (adding editable="true" to table, but its no good
The scenario is as follows: change some value of an input text , than click on table column header to do sort
Expectations: Inside detectSortEvent listener I see the updated value inside the list
Reality: Same old value in the list
Regards,
Daniel.

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

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

Resources