This question already has answers here:
Avoid back button on JSF web application
(2 answers)
Closed 1 year ago.
I'm having an issue with the back button, not keeping data in a dynamic dropdown in JSF on a request scoped bean.
I have a form with 2 dropdowns where dropdown2 is dynamic based on what is selected in dropdown1. Below is my code for these dropdowns.
<h:selectOneMenu id="group" label="group" value="#{queryBacking.groupInternalId}">
<f:ajax event="valueChange" render="membership" />
<f:selectItems value="#{supportBean.groupInstitutions}" var="group" itemValue="#{group.institutionInternalId}" itemLabel="#{group.institutionName}" />
</h:selectOneMenu>
<h:selectOneMenu id="membership" label="Membership" value="#{queryBacking.institutionInternalId}">
<f:selectItem itemLabel="Select One" itemValue="0" />
<f:selectItems value="#{queryBacking.groupMembershipInstitutions}" var="institution" itemValue="#{institution.institutionInternalId}" itemLabel="#{institution.institutionShortName}" />
</h:selectOneMenu>
My code works great except that if you submit the form and then click the back button, dropdown2 does not contain any values. How can fix this issue?
You mean the back button in the browser right?
The browser probably loads the page out of the browser cache. So you need to disable caching with a filter:
public class NoCacheFilter implements Filter {
private FilterConfig config;
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpRes = (HttpServletResponse) response;
if (!httpReq.getRequestURI().startsWith(
httpReq.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) {
httpRes.setHeader("Cache-Control",
"no-cache, no-store, must-revalidate"); // HTTP 1.1.
httpRes.setHeader("Pragma", "no-cache"); // HTTP 1.0.
httpRes.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response);
}
#Override
public void destroy() {
config = null;
}
#Override
public void init(FilterConfig config) throws ServletException {
this.config = config;
}
}
And then add this to the web.xml:
<filter>
<filter-name>NoCacheFilter</filter-name>
<filter-class>yourpackage.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
You can specify the pages you want filtered in <url-pattern> </url-pattern>
You can initialize the values for the page in the bean constructor:
TestBean class
#ManagedBean
#ViewScope
public class TestBean {
private String name;
public TestBean() {
//initialize the name attribute
//recover the value from session
HttpSession session = (HttpSession)FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
name = session.getAttribute("name");
if (name == null) {
name = "Luiggi";
}
}
public String someAction() {
//save the value in session
HttpSession session = (HttpSession)FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
session.setAttribute("name", name);
return "Test";
}
//getters and setters...
}
Test.xhtml
<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">
<h:body>
<h:outputText value="Hello " />
<h:outputText value="#{testBean.name}" />
<h:form>
<h:outputText value="Write your name: " />
<h:inputText value="#{testBean.name}" />
<br />
<h:commandButton value="Change name" action="#{testBean.someAction}" />
</h:form>
</h:body>
</ui:composition>
Adding an example to remove the session attribute before navigating to Text.xhtml
SomeBean class
#ManagedBean
#RequestScope
public class SomeBean {
public SomeBean() {
}
public String gotoTest() {
//removes an item from session
HttpSession session = (HttpSession)FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
session.removeAttribute("name");
return "Test";
}
}
SomeBean.xhtml
<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">
<h:body>
<h:form>
<!-- Every time you navigate through here, your "name"
session attribute will be removed. When you hit the back
button to get Test.xhtml you will see the "name"
session attribute that is actually stored. -->
<h:commandButton value="Go to Test" action="#{someBean.gotoTest}" />
</h:form>
</h:body>
</ui:composition>
Related
I need to display a message when LazyDataModel load method loads the data. I am using primefaces growl to display the message and updating it from load method using the below code, but It is not working (not seeing any message on UI). Please suggest what I am doing wrong, It seems something related to the asynchronous behaviour of load method but I am not sure how to fix it.
JSF Bean -
#ManagedBean(name = "cData")
#ViewScoped
public class DataPage implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2193735279937686495L;
#PostConstruct
public void init() {
FacesContext.getCurrentInstance().addMessage("growl-sticky", new
FacesMessage(FacesMessage.SEVERITY_INFO, "Sticky Message",
"Message Content from init"));
loadData();
}
private void loadData() {
FacesContext.getCurrentInstance().addMessage("growl-sticky", new
FacesMessage(FacesMessage.SEVERITY_INFO, "Sticky Message",
"Message loadData before load"));
setMobiles(new LazyDataModel<Mobile>() {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public List<Mobile> load(int first, int pageSize,
String sortField, SortOrder sortOrder,
Map<String, Object> filters) {
List<Mobile> data = new DataRepo().getMobileData();
mobiles.setRowCount(data.size());
FacesContext.getCurrentInstance().addMessage("growl-sticky", new
FacesMessage(FacesMessage.SEVERITY_INFO, "Sticky Message",
"Message Content from load"));
return data;
}
#Override
public Mobile getRowData(String rowKey) {
// some code
}
#Override
public Object getRowKey(Mobile object) {
// some code
}
});
}
public LazyDataModel<Mobile> getMobiles() {
return mobiles;
}
public void setMobiles(LazyDataModel<Mobile> mobiles) {
this.mobiles = mobiles;
}
private LazyDataModel<Mobile> mobiles = null;
}
xhtml page -
<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns = "http://www.w3.org/1999/xhtml"
xmlns:h = "http://java.sun.com/jsf/html"
xmlns:c = "http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>DataTable tag Example</title>
</h:head>
<h:body>
<h3>Mobile Details</h3>
<h:form>
<c:metadata>
<c:viewAction action="#{cData.showSticky}" />
</c:metadata>
<p:growl id="growl-sticky" showDetail="true" sticky="true" autoUpdate="true"/>
<p:commandButton actionListener="#{cData.showSticky}"
update="growl-sticky" value="Info" style="width: 10rem"
styleClass="ui-button-help" />
<h:dataTable value="#{cData.mobiles}" var="mobile" border="2" paginator="true" rows="10"
lazy="true">
<h:column>
<c:facet name="header">Name</c:facet>
#{mobile.companyname}
</h:column>
<h:column>
<c:facet name="header">Model Number</c:facet>
#{mobile.modelnumber}
</h:column>
<h:column>
<c:facet name="header">Color</c:facet>
#{mobile.color}
</h:column>
<h:column>
<c:facet name="header">Quantity</c:facet>
#{mobile.quantity}
</h:column>
<h:column>
<c:facet name="header">Price</c:facet>
#{mobile.price}
</h:column>
</h:dataTable>
</h:form>
</h:body>
</html>
The issue why your message doesn't show up is because of the phase when Load is called. Explanation and workaround below.
The load method is invoked in RENDER_RESPONSE phase, which is inconvenient because error messages could occur here and they would not typically be rendered because p:messages are in most cases rendered as one of first components.
Issue: https://github.com/primefaces/primefaces/issues/3501
Workaround: https://github.com/primefaces/primefaces/issues/3501#issuecomment-469731529
I have a problem with CDI scope.
I have a bean with conversation scoped, ClientController, where I have client and phone object to be push in a service order. When I register a new client, I can push one or more phones to this client. For this, I have used conversation scope. However each request to push a new phone to my client is executing the #PostContruct method, doing the bean lose its state, even I am giving begin on the conversation when I push the first phone.
At first, I guess the problem was the bean configuration, but when I removed the template that was declared on the client page, the application works correct. This template use a bean with session scope, to control the page language by the user choice.
Next has my code, and you can follow my code on github repository by this link https://github.com/mcqueide/service-order.
ClientController.java
package br.com.codeshare.controller;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.inject.Produces;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import br.com.codeshare.enums.ErrorCode;
import br.com.codeshare.exception.BusinessException;
import br.com.codeshare.model.Client;
import br.com.codeshare.model.Phone;
import br.com.codeshare.qualifiers.SessionMap;
import br.com.codeshare.service.ClientService;
import br.com.codeshare.service.PhoneService;
import br.com.codeshare.util.WebResources;
#Named
#ConversationScoped
public class ClientController implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private FacesContext facesContext;
#Inject #SessionMap
private Map<String, Object> sessionMap;
#Inject
private ClientService clientService;
private Client newClient;
#Inject
private PhoneController phoneController;
#Inject
private PhoneService phoneService;
#Inject
private Conversation conversation;
private String filterName;
private List<Client> listClients;
private Client clientSelected;
private List<Phone> phoneToBeRemove;
#Produces
#Named
public Client getNewClient() {
return newClient;
}
#PostConstruct
public void initNewClient() {
newClient = new Client();
newClient.setTelefones(new ArrayList<Phone>());
listClients = clientService.findAll();
}
public String save() throws Exception {
try {
validatePhoneLeastOnePhoneObligatory(newClient);
clientService.save(newClient);
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, WebResources.getMessage("register"),WebResources.getMessage("sucess_register")));
initNewClient();
}catch (BusinessException e) {
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,WebResources.getMessage(e.getErrorCode()),"");
facesContext.addMessage(null, m);
}catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,errorMessage,WebResources.getMessage("unsuccessful"));
facesContext.addMessage(null, m);
}
if(!conversation.isTransient()){
conversation.end();
}
return null;
}
public String update(Client client) throws Exception{
try {
validatePhoneLeastOnePhoneObligatory(client);
clientService.update(client,phoneToBeRemove);
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, WebResources.getMessage("register"),WebResources.getMessage("sucess_register")));
initNewClient();
}catch (BusinessException e) {
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,WebResources.getMessage(e.getErrorCode()),"");
facesContext.addMessage(null, m);
return null;
} catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, WebResources.getMessage("unsuccessful"));
facesContext.addMessage(null, m);
return null;
}
if(!conversation.isTransient()){
conversation.end();
}
return "clients";
}
private void validatePhoneLeastOnePhoneObligatory(Client client) throws BusinessException {
if(client.getHomePhone().isEmpty() && client.getBisenessPhone().isEmpty()){
throw new BusinessException(ErrorCode.LEAST_ONE_PHONE_OBLIGATORY.getErrorCode());
}
}
private String getRootErrorMessage(Exception e) {
String errorMessage = "Registration failed. See server log for more information";
if (e == null) {
return errorMessage;
}
Throwable t = e;
while (t != null) {
errorMessage = t.getLocalizedMessage();
t = t.getCause();
}
return errorMessage;
}
public void addClientPhone() {
if(conversation.isTransient()){
conversation.begin();
}
phoneController.getNewPhone().setClient(newClient);
if (newClient.getPhones() == null) {
newClient.setTelefones(new ArrayList<Phone>());
}
newClient.getPhones().add(phoneController.getNewPhone());
phoneController.initNewPhone();
}
public void removeClientPhone(Phone phone){
if(conversation.isTransient()){
conversation.begin();
}
clientSelected.getPhones().remove(phone);
if(phoneToBeRemove == null){
phoneToBeRemove = new ArrayList<Phone>();
}
phoneToBeRemove.add(phone);
}
public void addClientPhoneOnUpdate() {
if(conversation.isTransient()){
conversation.begin();
}
phoneController.getNewPhone().setClient(clientSelected);
if (clientSelected.getPhones() == null) {
clientSelected.setTelefones(new ArrayList<Phone>());
}
clientSelected.getPhones().add(phoneController.getNewPhone());
phoneController.initNewPhone();
}
public void searchByName() {
listClients = null;
if(filterName == null){
listClients = clientService.findAll();
}
listClients = clientService.findByName(filterName);
}
public String edit(Client client) {
if(conversation.isTransient()){
conversation.begin();
}
this.clientSelected = client;
List<Phone> phoneList = phoneService.findPhoneByClientId(clientSelected.getId());
clientSelected.setTelefones(phoneList);
sessionMap.put("client", client);
return "update_client";
}
public Client getClientSelected() {
return (Client) sessionMap.get("client");
}
public String getFilterName() {
return filterName;
}
public void setFilterName(String filterName) {
this.filterName = filterName;
}
public List<Client> getListClients() {
return listClients;
}
}
Language.java
package br.com.codeshare.util;
import java.io.Serializable;
import java.util.Locale;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
#Named
#SessionScoped
public class Language implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private FacesContext facesContext;
#PostConstruct
public void init(){
localeCode = "pt";
countryLocaleCodeChanged();
}
private String localeCode;
public String getLocaleCode() {
return localeCode;
}
public void setLocaleCode(String localeCode) {
this.localeCode = localeCode;
}
// value change event listener
public void countryLocaleCodeChanged() {
facesContext.getViewRoot().setLocale(new Locale(localeCode));
}
}
client.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets" template="/template.xhtml">
<ui:define name="titulo">
#{label['client.title']}
</ui:define>
<ui:define name="body">
<h:form id="form">
<p:messages />
<p:fieldset legend="#{label['client.fieldset.client']}" id="client">
<p:panelGrid columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="name" value="#{label['client.name']}" />
<p:inputText id="name" value="#{newClient.name}" />
<p:outputLabel for="adress" value="#{label['client.adress']}" />
<p:inputText id="adress" value="#{newClient.adress}" />
<p:fragment rendered='#{!language.localeCode.equals("en")}'>
<p:panelGrid columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="homePhone_pt" value="#{label['client.homePhone']}" />
<p:inputMask id="homePhone_pt" value="#{newClient.homePhone}" mask="(99)99999-9999"/>
<p:outputLabel for="bisenessPhone_pt" value="#{label['client.businessPhone']}" />
<p:inputMask id="bisenessPhone_pt" value="#{newClient.bisenessPhone}" mask="(99)9999-9999"/>
</p:panelGrid>
</p:fragment>
<p:fragment rendered='#{language.localeCode.equals("en")}'>
<p:panelGrid columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="homePhone_en" value="#{label['client.homePhone']}" />
<p:inputText id="homePhone_en" value="#{newClient.homePhone}"/>
<p:outputLabel for="bisenessPhone_en" value="#{label['client.businessPhone']}" />
<p:inputText id="bisenessPhone_en" value="#{newClient.bisenessPhone}"/>
</p:panelGrid>
</p:fragment>
</p:panelGrid>
</p:fieldset>
<p:fieldset legend="#{label['client.fieldset.phone']}" id="phones">
<p:panelGrid id="phone" columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="brand" value="#{label['phone.brand']}" />
<p:inputText id="brand" value="#{newPhone.brand}" />
<p:outputLabel for="model" value="#{label['phone.model']}" />
<p:inputText id="model" value="#{newPhone.model}" />
<p:outputLabel for="state" value="#{label['phone.state']}"/>
<p:selectOneRadio id="state" value="#{newPhone.state}">
<f:selectItems value="#{phoneStates}" var="p" itemValue="#{p}" itemLabel="#{label[p.label]}" />
</p:selectOneRadio>
<p:outputLabel for="esn" value="#{label['phone.esn']}" />
<p:inputText id="esn" value="#{newPhone.esn}" />
</p:panelGrid>
<p:commandButton value="#{label['phone.add']}" action="#{clientController.addClientPhone}" update="phoneTable phones"/>
<p:dataTable value="#{newClient.phones}" var="phone" emptyMessage="#{label['phone.notadd']}"
id="phoneTable">
<p:column headerText="#{label['phone.brand']}">
<p:outputLabel value="#{phone.brand}"/>
</p:column>
<p:column headerText="#{label['phone.model']}">
<p:outputLabel value="#{phone.model}"/>
</p:column>
</p:dataTable>
</p:fieldset>
<p:commandButton action="#{clientController.save}" value="#{label['client.save']}" update="#form"/>
</h:form>
</ui:define>
</ui:composition>
template.xhtml
<?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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:view locale="#{language.localeCode}" encoding="utf-8">
<h:head>
<title>
<ui:insert name="title"/>
</title>
<link rel="stylesheet" type="text/css" href="resources/css/reset.css" />
<link rel="stylesheet" type="text/css" href="resources/css/style.css" />
<link rel="stylesheet" type="text/css" href="resources/css/fonts/font-awesome.min.css" />
</h:head>
<body>
<div class="main">
<div class="menu">
<ui:include src="/menu.xhtml" />
</div>
<div id="body">
<ui:insert name="body"/>
</div>
</div>
</body>
</f:view>
</html>
menu.xhtml
<?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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition>
<p:menubar>
<p:submenu label="#{label['menu.serviceorder']}">
<p:menuitem value="#{label['menu.serviceorder']}" url="/service-order.jsf"/>
<p:menuitem value="#{label['menu.serviceorder.new']}" url="/new-service-order.jsf"/>
</p:submenu>
<p:submenu label="#{label['menu.client']}">
<p:menuitem value="#{label['menu.client.new']}" url="/client.jsf"></p:menuitem>
<p:menuitem value="#{label['menu.clients']}" url="/clients.jsf"></p:menuitem>
</p:submenu>
</p:menubar>
<h:form class="menu_languages">
<p:selectOneMenu value="#{language.localeCode}">
<f:selectItem itemLabel="Português" itemValue="pt" />
<f:selectItem itemLabel="English" itemValue="en" />
<p:ajax listener="#{language.countryLocaleCodeChanged}" update="#all" />
</p:selectOneMenu>
</h:form>
</ui:composition>
</html>
I am pretty convinced that you are running into one of the following problems:
Conversation ends
try to play with some #PreDestroy methods to see when does the conversation vanish
make sure you do not end() conversations earlier (checking your code that would mean calling save/update)
New conversation is created every time you add phone (this is most likely the cause)
when you want another request to be associated with your running conversation, you need to make use of conversation ID (propagate it)
note that you can obtain the ID by calling conversation.getId()
to verify this, check that your URL contains the given conversation ID
also note that if you every time create a new Conversation, the old long-running ones are still hanging in there
Propagation of Conversation is done by appending a cid (conversation ID) to the request URL. Here is a quote from CDI spec (which I suggest you read) explaining when is conversation propagated automatically:
If the current Servlet request is a JSF request, and the conversation is in long-running state, it is propagated according to the following rules:
The long-running conversation context associated with a request that renders a JSF view is automatically propagated to any faces request (JSF form submission) that originates from that rendered page.
The long-running conversation context associated with a request that results in a JSF redirect (a redirect resulting from a navigation rule or JSF NavigationHandler) is automatically propagated to the resulting non-faces request, and to any other subsequent request to the same URL. This is accomplished via use of a request parameter named cid containing the unique identifier of the conversation.
I could resolved this with this:
<f:metadata>
<f:event listener="#{clientController.initConversation()}" type="preRenderView" />
</f:metadata>
Now when my page is render, I have my cid on my post action. But I don’t know if it is the better way to resolve this, because I want to transform my transaction in long-running just when the user click to add a phone, so if someone has a better idea, share please.
I have a <h:selectBooleanCheckBox> as part part of my JSF which I want to run a bean method when it's state has changed from unchecked to checked.
I have the following controller bean
#Named
#ViewScoped
public class UserController {
#Inject
private UserService userService;
#Inject
private LocationService locationService;
private UserFilter userFilter;
private List<User> users;
private List<Location> locations;
#PostConstruct
public void init() {
users = userService.listAll();
locations = locationService.listAll();
userFilter = new UserFilter();
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public List<Location> getLocations() {
return locations;
}
public void setLocations(List<Location> locations) {
this.locations = locations;
}
public void listAllUsers() {
users = userService.listAll();
}
public void findUsers() {
// code that uses the UserFilter
// to decide which user filter find method to use
}
}
The UserFilter is a simple DTO
public class UserFilter {
private boolean allUsers = true;
private String username;
private String location;
//getters and setters
}
And my JSF has is like so
<?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://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Users</title>
</h:head>
<h:body>
<h1>Users</h1>
<h:form id="filterForm">
<h:selectBooleanCheckbox id="selectAll" value="#{userController.userFilter.allUsers}" title="allUsers">
<f:ajax render="filterGrid"/>
</h:selectBooleanCheckbox><h:outputText value ="All users"/>
<h:panelGrid id="filterGrid" columns="3">
<h:inputText id="userName" value="#{userController.userFilter.userName}" disabled="#{userController.userFilter.allUsers}"/>
<h:selectOneMenu id="selectLocation" value="#{userController.userFilter.location}" disabled="#{userController.userFilter.allUsers}">
<f:selectItems value="#{userController.locations}" var="location" itemValue="#{location.location}" itemLabel="#{location.location}"/>
</h:selectOneMenu>
<h:commandButton value="Filter" disabled="#{userController.userFilter.allUsers}" action="#{userController.findUsers()}"/>
</h:panelGrid>
</h:form>
<h:form rendered="#{not empty userController.users}">
<h:dataTable value="#{userController.users}" var="user">
<h:column>#{user.name}</h:column>
<h:column>#{user.location.location}</h:column>
<h:column><h:commandButton value="delete" action="#{userController.delete(user)}"/></h:column>
</h:dataTable>
</h:form>
<h:panelGroup rendered="#{empty userController.users}">
<p>Table is empty! Please add new items.</p>
</h:panelGroup>
<h3>Add user</h3>
<h:form id="user">
<p>Value: <h:inputText id="name" /></p>
<p>
<h:commandButton value="add" action="#{userController.add(param['user:name'])}"/>
</p>
</h:form>
</h:body>
</html>
As you can see by default it lists all users, then when the checkbox is unchecked you have the option to filter on username/location.
What I want is for the check box to run the userController.listAllUsers() method when it's state moves from unchecked to checked.
And a small additional question, how do I get the checkbox to appear in the same row as the panel grid items?
I have a habit of answering my own questions it seems! I needed an additional <f:ajax tag that rendered the user form and had the listener attribute set
So something like
<h:selectBooleanCheckbox id="selectAll" value="#{userController.userFilter.allUsers}" title="allUsers">
<f:ajax render="filterGrid"/>
<f:ajax render="usersForm" listener="#{userController.listAllUsers()}"/>
</h:selectBooleanCheckbox><h:outputText value ="All users"/>
I have a JSF application where you enter 2 numbers (index.xhtml), and when you click "Add" button those numbers are added and the result is shown in a new page (resultado.xhtml).
What I want to do is that when you insert the 2 numbers, click "Add" button and go to resultado.xhtml, if you go back to index.xhtml, clicking going back button in you browser, the inputText fields must be empty and not containing the previously inserted values. The problem is that it works with Firefox, but not with Chromium and Konqueror browsers. When I use this browser and press going back button the numbers inserted are in the inputText. How could make it work with all the browsers?
I have followed this link to implement a servlet filter to clear cache: Prevent user from seeing previously visited secured page after logout
index.xhtml
<h:head>
<h:outputStylesheet library="css" name="styles.css" />
</h:head>
<h:body>
<h:form>
<!--Number 1 -->
<h:inputText id="num1" label="num1" required="true" size="5" maxlength="5"
styleClass="#{component.valid ? '' : 'validation-failed'}"
value="#{sumaManagedBean.number1}"
requiredMessage="You must enter a value"/>
</h:inputText>
<h:message for="num1" />
<!--Number 2-->
<h:inputText id="num2" label="num2" required="true" size="5" maxlength="5"
styleClass="#{component.valid ? '' : 'validation-failed'}"
value="#{sumaManagedBean.number2}"
requiredMessage="You must enter a value">
</h:inputText>
<h:message for="num2" />
<h:commandButton value="Add" action="#{sumaManagedBean.direccionPagina()}"/>
</h:form>
</h:body>
resultado.xhtml
<h:head>
<h:outputStylesheet library="css" name="styles.css" />
</h:head>
<h:body>
<h:outputText value="Add correct" rendered="#{sumaManagedBean.insertCorrecto}" styleClass="message"/>
Result:
<h:outputText value="#{sumaManagedBean.calcularResultado()}" />
</h:body>
sumaManagedBean.java. My ManagedBean scope is RequestScope.
package controllers;
//Imports
#ManagedBean
#RequestScoped
public class SumaManagedBean implements Serializable
{
boolean m_binsertCorrecto;
int number1;
int number2;
public SumaManagedBean() {
}
//Getters and Setters
public int getNumber1() {
return number1;
}
public void setNumber1(int number1) {
this.number1 = number1;
}
public int getNumber2() {
return number2;
}
public void setNumber2(int number2) {
this.number2 = number2;
}
//
public boolean isInsertCorrecto()
{
return m_binsertCorrecto;
}
public void setInsertCorrecto(boolean bInsertCorrecto)
{
this.m_binsertCorrecto = bInsertCorrecto;
}
public int calcularResultado()
{
int resultado;
resultado = number1 + number2;
return resultado;
}
public String direccionPagina()
{
String direccion = "/resultado";
setInsertCorrecto(true);
return direccion;
}
}
NoCacheFilter.java
package filters;
import java.io.IOException;
import javax.faces.application.ResourceHandler;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#WebFilter("/*") //Apply a filter for all URLs
public class NoCacheFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (!request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
On the datable I click on commandLink and that link navigates to destination page. I need to get the parameter ('id' in this case) on that destination page.
It works fine with link but not with commandLink. I get the parameter as null. And I must solve this with commandLink.
source page
<p:dataTable value="#{orderBean.orders}" var="order" id="orderDTable" rowKey="#{order.id}">
<p:column id="editButtonsId" >
<p:commandLink value="Edit" action="orderInsert" >
<f:param name="id" value="#{order.id}"/>
</p:commandLink>
<!-- works fine with this link -->
<p:link value="Edit" outcome="orderInsert" >
<f:param name="id" value="#{order.id}" />
</p:link>
</p:column>
</p:dataTable>
destination page
<ui:composition template="templates/layout.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:components="http://java.sun.com/jsf/composite/components"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:p="http://primefaces.org/ui">
<f:metadata>
<f:viewParam name="id" value="#{orderInsertBean.id}" />
<f:event listener="#{orderInsertBean.init}" type="preRenderView" />
</f:metadata>
</ui:composition>
#Component("orderInsertBean")
#ManagedBean
#RequestScoped
public class OrderInsertBean implements Serializable {
private String id;
public void init() {
// the parameter id is null here when the page is navigated by the commandLink
FacesMessage msg = new FacesMessage(id, null);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public String getId() { return id; }
public void setId(String id) { this.id = id; }
}
See these posts first
Semantics of "?faces-redirect=true" in <commandlink action=...> and why not use it everywhere
f:param does not work with p:commandLink or h:commandLink on query string
With commandLink you could either annotate the id with #ManagedPropertyas shown here or use the request parameters map:
public void init() {
FacesContext context = FacesContext.getCurrentInstance();
Map requestParams = context.getExternalContext().getRequestParameterMap();
id = (String) requestParams.get("id");
// the parameter id is null here when the page is navigated by the commandLink
FacesMessage msg = new FacesMessage(id, null);
FacesContext.getCurrentInstance().addMessage(null, msg);
}