How to add Faceslets message on different messages component? - jsf

I would like to have different messages on different message components, but unfortunately message always display on both message components.
TestFaces.java
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
#javax.enterprise.context.RequestScoped
#javax.inject.Named
public class TestFaces implements java.io.Serializable {
static final long serialVersionUID = 1L;
static final Logger logger = LogManager.getLogger();
public String callMsg001() {
FacesContext.getCurrentInstance().addMessage("msg001",
new FacesMessage(FacesMessage.SEVERITY_INFO, "This is msg001", null));
return null;
}
public String callMsg002() {
FacesContext.getCurrentInstance().addMessage("msg002",
new FacesMessage(FacesMessage.SEVERITY_INFO, "This is msg002", null));
return null;
}
}
index.html
<!DOCTYPE HTML>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Index</title>
</h:head>
<h:body>
<h:form>
msg001: <h:messages id="msg001" style="msg001" />
msg002: <h:messages id="msg002" style="msg002"/>
<h:commandButton
value="Trigger msg001"
action="${testFaces.callMsg001()}">
</h:commandButton>
<h:commandButton
value="Trigger msg002"
action="${testFaces.callMsg002()}">
</h:commandButton>
</h:form>
</h:body>
</html>
Output
I would like to have different messages on different message components.

Thanks to #WoAiNii
Working example as below.
TestFaces.java
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
#javax.enterprise.context.RequestScoped
#javax.inject.Named
public class TestFaces implements java.io.Serializable {
static final long serialVersionUID = 1L;
public String callCmd001() {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO, "This is global cmd001", null));
FacesContext.getCurrentInstance().addMessage("form001:cmd001",
new FacesMessage(FacesMessage.SEVERITY_INFO, "This is cmd001", null));
return null;
}
public String callCmd002() {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO, "This is global cmd002", null));
FacesContext.getCurrentInstance().addMessage("form001:cmd002",
new FacesMessage(FacesMessage.SEVERITY_INFO, "This is cmd002", null));
return null;
}
}
index.html
<!DOCTYPE HTML>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
<title>Message Test</title>
</h:head>
<h:body>
<h:form id="form001">
msgs: <h:messages/><br/>
msgs global Only: <h:messages globalOnly="true"/><br/>
msg001: <h:message for="form001:cmd001"/><br/>
msg002: <h:message for="form001:cmd002"/><br/>
<h:commandButton id="cmd001"
value="call cmd001"
action="${testFaces.callCmd001()}">
</h:commandButton>
<h:commandButton id="cmd002"
value="call cmd002"
action="${testFaces.callCmd002()}">
</h:commandButton>
</h:form>
</h:body>
</html>

Related

How to submit JSF ajax with inputs from multiple forms?

Due to UI layout issue, I have to separate inputs into multiple form. How to submit JSF ajax with inputs from multiple forms?
Based on sample code below, how to get form1 input1 value when click on the Ajax Call button in form2?
Weblogic 12.2 Java 8 Servlet 3.1 JSF 2.2 CDI 1.1 EJB 3.2
JSF Page
<!DOCTYPE HTML>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:jsf="http://xmlns.jcp.org/jsf"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions">
<h:head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0" />
<title>Ajax Test</title>
</h:head>
<h:body>
<ui:debug hotkey="x" />
<h:messages id="msg" />
<fieldset>
<legend>Form 1</legend>
<h:form
id="form1"
method="get">
<h:inputText
id="input1"
value="#{ajaxTestBean.input1}" />
<h:commandButton
value="Standard call"
action="#{ajaxTestBean.call}" />
</h:form>
</fieldset>
<fieldset>
<legend>Form 2</legend>
<h:form
id="form2"
method="get">
<h:inputText
id="input2"
value="#{ajaxTestBean.input2}" />
<h:commandButton value="Ajax Call">
<f:ajax
execute="form1:input1 form2:input2"
render="msg form1:input1 form2:input2"
listener="#{ajaxTestBean.callAjax}" />
</h:commandButton>
</h:form>
</fieldset>
</h:body>
</html>
Java Class
package dev;
import javax.faces.event.AjaxBehaviorEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
#javax.inject.Named("ajaxTestBean")
#javax.faces.view.ViewScoped
public class AjaxTestBean implements java.io.Serializable {
static final long serialVersionUID = 1L;
static final Logger logger = LogManager.getLogger();
String input1;
String input2;
public AjaxTestBean() {
}
public void call() {
logger.traceEntry();
logger.debug("input1: {}", this.input1);
logger.debug("input2: {}", this.input2);
logger.traceExit();
}
public void callAjax(AjaxBehaviorEvent event) {
logger.traceEntry();
logger.debug("input1: {}", this.input1);
logger.debug("input2: {}", this.input2);
logger.traceExit();
}
public String getInput1() {
return input1;
}
public void setInput1(String input1) {
this.input1 = input1;
}
public String getInput2() {
return input2;
}
public void setInput2(String input2) {
this.input2 = input2;
}
}

JSF CDI Conversation scope

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.

Primefaces: open a dialog when an element in a pie chart is clicked

I'm trying to figure out how to open a dialog box when an element in a pie chart is clicked. I'm new to Primefaces, so most of what I've found in searches are more complex examples than what I'm trying to accomplish. The dialog box is opened using the Dialog Framework. I've been able to open the dialog via a command button no problem, so I'm pretty sure the problem isn't with the dialog itself.
Here's the initial page:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<body>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:p="http://primefaces.org/ui"
xmlns:pm="http://primefaces.org/mobile"
>
<p:panel header="Dashboard" toggleable="true">
<h:form>
<p:growl id="growl" showDetail="true" />
<h:panelGrid columns="2">
<p:chart type="pie" model="#{dashboardPieChart.pieModel1}" style="width:350px; height:200px" >
<p:ajax event="itemSelect" listener="#{dashboardPieChart.itemSelect}"/>
</p:chart>
</h:panelGrid>
<h:outputText id="out" value="#{dashboardPieChart.seriesText}" />
</h:form>
</p:panel>
<script type="text/javascript">
PrimeFaces.info ('Info message');
PrimeFaces.debug('Debug message');
PrimeFaces.warn ('Warning message');
PrimeFaces.error('Error message');
</script>
</ui:composition>
</body>
</html>
And the backing bean:
package com.company.project.model;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import org.primefaces.context.RequestContext;
import org.primefaces.event.ItemSelectEvent;
import org.primefaces.model.chart.PieChartModel;
#ManagedBean
#ViewScoped
public class DashboardPieChart implements Serializable {
private static final long serialVersionUID = -9056199453379512637L;
private PieChartModel pieModel1;
private String seriesText;
/*
public DashboardPieChart()
{
init();
}
*/
#PostConstruct
public void init() {
System.out.println("DashboardPieChart - inside init()");
createPieModels();
}
public PieChartModel getPieModel1() {
return pieModel1;
}
private void createPieModels() {
createPieModel1();
}
private void createPieModel1() {
pieModel1 = new PieChartModel();
pieModel1.set("Proposals in Progress", 12);
pieModel1.set("Proposals Completed", 15);
pieModel1.setTitle("Proposals");
pieModel1.setLegendPosition("w");
pieModel1.setDiameter(100);
}
public void itemSelect(ItemSelectEvent event) {
String msgText = "Item Index: " + event.getItemIndex() + ", Series Index:" + event.getSeriesIndex();
System.out.println (msgText);
this.seriesText = msgText;
RequestContext.getCurrentInstance().openDialog("pieChartDrillDownDialog");
}
public String getSeriesText() {
return seriesText;
}
public void setSeriesText(String seriesText) {
this.seriesText = seriesText;
}
}
and this is the dialog I'm trying to open:
<!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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:pm="http://primefaces.org/mobile"
>
<h:head>
<title>Proposal Status Detail</title>
</h:head>
<h:body>
<h:form>
<p:chart type="pie" model="#{dashboardPieChartDrillDown.pieModel}" style="width:350px; height:200px" >
</p:chart>
</h:form>
</h:body>
</html>
I was able to make it work using remoteCommand:
XHTML:
<p:remoteCommand name="fnc" actionListener="#{playgroundController.showDialog()}"/>
<p:chart type="pie" model="#{playgroundController.pieModel1}" style="width:400px;height:300px">
<p:ajax event="itemSelect" listener="#{playgroundController.itemSelect}" oncomplete="fnc()" />
</p:chart>
BEAN:
public void showDialog() {
RequestContext.getCurrentInstance().openDialog("pieChartDrillDownDialog");
}
public void itemSelect(ItemSelectEvent event) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Item selected",
"Item Index: " + event.getItemIndex() + ", Series Index:" + event.getSeriesIndex());
FacesContext.getCurrentInstance().addMessage(null, msg);
}

how to force refresh of my screen in JSF

in my JSF2 app I have ​​screens composed with :
Header
Body
In the header I have a combo list. At each change in value in the combo list I have an Ajax request that updates the data in the Body. So far everything is working properly. Now the home screen's structure should be change when the value of combo list change. To do this I have :
1 ManagedBean HomeBean that manage the home
1 ManagedBean HeaderBean that manage the header
2 object HomeScreen1.java and HomeScreen2.java that allows me to valued data from each screen
2 services HomeScreen1Loader.java and HomeScreen2Loader.java that manage loading of each type of screen
1 template home.xhtml
2 fichier home1.xhtml et home2.xhtml
When I log in to the application, I get the good page corresponding (Element type 1 => home page 1). But when I select a type 2 item, the actionListener methode is execute, ManagedBean's data was updated (for type 2 screen) , but the page does not updated. What do you do ?
HeaderBean.java :
package com.omb.view;
import java.io.Serializable;
import java.util.List;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.omb.exception.TechnicalException;
import com.omb.view.util.Constants;
import com.omb.view.util.FacesUtils;
#Controller
#Scope("session")
public class HeaderBean implements Serializable {
private static final long serialVersionUID = 1L;
private static final Log logger = LogFactory.getLog(HeaderBean.class);
private List<SelectItem> elementsDisplayed;
public void initComboList() throws FunctionnalException {
// init the combo list
}
public void elementChangeListener(ValueChangeEvent event) {
if (event.getNewValue() != null) {
// Do traitement....
ContextBean contextBean = (ContextBean) FacesUtils.getObjectInSession(ContextBean.CONTEXT_BEAN_NAME);
AbstractBean currentBean = (AbstractBean) FacesUtils.getObjectInSession(contextBean
.getCurrentBeanInSession());
try {
currentBean.refresh();
} catch (TechnicalException e) {
logger.error(e.getMessage(), e);
}
}
}
public String disconnect() {
FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "/login.xhtml?faces-redirect=true";
}
public List<SelectItem> getElementsDisplayed() {
return elementsDisplayed;
}
public void setElementsDisplayed(List<SelectItem> elementsDisplayed) {
this.elementsDisplayed = elementsDisplayed;
}
}
ContextBean.java :
package com.omb.view;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.omb.view.util.Constants;
#Controller
#Scope("session")
public class ContextBean {
public final static String CONTEXT_BEAN_NAME = "contextBean";
private String templateHomeName;
private boolean defaultHome;
public String getTemplateHomeName() {
return this.templateHomeName;
}
public void setTemplateHomeName(String templateHomeName) {
this.templateHomeName = templateHomeName;
}
public boolean isDefaultHome() {
return this.defaultHome;
}
public void setDefaultHome(boolean defaultHome) {
this.defaultHome = defaultHome;
}
}
HomeBean.java :
package com.omb.view.home;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.omb.exception.FunctionnalException;
import com.omb.exception.TechnicalException;
import com.omb.view.AbstractBean;
import com.omb.view.util.Constants;
#Controller
#Scope("session")
public class HomeBean extends AbstractBean {
private static final Log logger = LogFactory.getLog(HomeBean.class);
public static final String HOME_1_NAME = "home1.xhtml";
public static final String HOME_2_NAME = "home2.xhtml";
#Autowired
private HomeScreen1 homeScreen1;
#Autowired
private HomeScreen2 homeScreen2;
#SuppressWarnings({"unchecked", "rawtypes"})
public String display() throws TechnicalException, FunctionnalException {
ContextBean context = (ContextBean) FacesUtils.getObjectInSession(ContextBean.CONTEXT_BEAN_NAME);
if (!isInitialized()) {
if (defaultHomeScreen == null) {
defaultHomeScreen = new DefaultHomeScreen();
}
if (eurHomeScreen == null) {
eurHomeScreen = new EurHomeScreen();
}
AbstractHomeScreenLoader loader = HomeScreenLoaderFactory.getLoader(getTypeElement());
if (Constants.CODE_TYPE_1.equals(getTypeElement()) {
loader.load(homeScreen1);
context.setTemplateHomeName(HOME_1_NAME);
} else {
loader.load(homeScreen2);
context.setTemplateHomeName(HOME_2_NAME);
}
setInitialized(true);
} else if (!upToDate) {
refresh();
}
return "home";
}
#SuppressWarnings({"unchecked", "rawtypes"})
public void refresh() throws TechnicalException {
upToDate = true;
AbstractHomeScreenLoader loader = HomeScreenLoaderFactory.getLoader(getTypeElement());
if (Constants.CODE_TYPE_1.equals(userContext.getCurrentHotelCountryId())) {
loader.refresh(homeScreen1);
} else {
loader.refresh(homeScreen2);
}
}
public HomeScreen1 getHomeScreen1() {
return this.homeScreen1;
}
public void setHomeScreen1(HomeScreen1 homeScreen1) {
this.homeScreen1 = homeScreen1;
}
public HomeScreen2 getHomeScreen2() {
return this.homeScreen2;
}
public void setHomeScreen2(HomeScreen2 homeScreen2) {
this.homeScreen2 = homeScreen2;
}
}
layout.xhtml main template of the application :
<?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:ui="http://java.sun.com/jsf/facelets"
xmlns:ice="http://www.icesoft.com/icefaces/component">
<h:head>
<title><ui:insert name="title">OMB</ui:insert></title>
<ice:outputStyle href="/xmlhttp/css/xp/xp.css" rel="stylesheet" type="text/css" />
<link type="text/css" rel="stylesheet"
href="#{facesContext.externalContext.requestContextPath}/resources/css/style.css" />
</h:head>
<h:body>
<h:panelGroup id="page" styleClass="mainMaster" layout="block">
<h:panelGroup id="header" styleClass="header" layout="block">
<ui:insert name="header">
<ui:include
src="/pages/layer/header/#{contextBean.templateHeaderName}" />
</ui:insert>
</h:panelGroup>
<h:panelGroup id="headerMenu" styleClass="menu" layout="block">
<ui:insert name="buttons">
<ui:include
src="/pages/layer/menu/#{contextBean.templateMenuButtonName}" />
</ui:insert>
</h:panelGroup>
<h:panelGroup id="main" styleClass="mainContent" layout="block">
<h:panelGroup id="content" styleClass="content" layout="block">
<ui:insert name="content" />
</h:panelGroup>
</h:panelGroup>
<h:panelGroup id="footer" styleClass="footer" layout="block">
<ui:insert name="footer">
<ui:include src="/pages/layer/footer/footer.xhtml" />
</ui:insert>
</h:panelGroup>
</h:panelGroup>
</h:body>
</html>
header.xhtml, page which manage the combo list:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets">
<body>
<ui:composition>
<ice:form id="headerForm" xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ace="http://www.icefaces.org/icefaces/components"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:panelGroup styleClass="logo" layout="block">
<ice:graphicImage styleClass="imgLogoHR"
value="#{facesContext.externalContext.requestContextPath}/resources/images/common/logo/Logo.png" />
<h:panelGroup styleClass="loginArea" layout="block">
<h:panelGroup styleClass="area" layout="block">
<h:panelGroup styleClass="comboHotel" layout="block">
<ace:simpleSelectOneMenu id="selectCurrentElement"
value="#{headerBean.currentElementDisplayed}"
valueChangeListener="#{headerBean.elementChangeListener}"
labelPosition="left" indicatorPosition="left" required="false"
rendered="#{not empty headerBean.elementsDisplayed}">
<f:selectItems value="#{headerBean.elementsDisplayed}" />
<ace:ajax execute="#this" render="#all" />
</ace:simpleSelectOneMenu>
</h:panelGroup>
</h:panelGroup>
</h:panelGroup>
</h:panelGroup>
</ice:form>
</ui:composition>
</body>
</html>
home.xhtml main template of home page and component should be refresh:
<?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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns:ace="http://www.icefaces.org/icefaces/components">
<h:body>
<ui:composition template="/pages/layer/layout.xhtml">
<ui:define name="content">
<ui:include
src="/pages/home/#{contextBean.templateHomeName}" />
</ui:define>
</ui:composition>
</h:body>
</html>
I found the solution, the problem came to the ManagedBean ContextBean's templateHomeName attribute that was not properly valued. I added in loader.load(homeScreen1) and refresh and everything it's ok. I should upgrade my JSF version : 2.1.0-b11 to 2.1.26 because I had an error when refresh.

p:remoteCommand destroys #ViewScoped managed bean

I am having trouble adding a p:remoteCommand to a form. It looks something like:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:util="http://java.sun.com/jsf/composite/components/util"
xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Reset Test</title>
<link type="text/css" rel="stylesheet" href="/treetable-sscce/css/example.css" />
<h:outputScript library="primefaces" name="jquery/jquery.js"/>
</h:head>
<div class="box">
<h2>Box</h2>
<h:panelGroup id="mypanel">
Headline: <h:outputText value="#{resetBean.headline}" />
<br/>
Message : <h:outputText value="#{resetBean.message}" />
<br/>
</h:panelGroup>
</div>
<div class="box">
<h2>Form</h2>
<h:form id="myform" acceptcharset="utf-8">
<p:growl id="growl" showDetail="true" sticky="false" severity="info, warn" />
<!-- register custom validate event -->
<f:event listener="#{resetBean.validateForm}" type="postValidate" />
<p:remoteCommand name="resetByEscape" action="#{resetBean.resetAction}"
immediate="true" update=":myform :mypanel" />
<h:outputLabel for="headline">Meldungsüberschrift</h:outputLabel>
<h:inputText id="headline" value="#{resetBean.headline}" />
<br/>
<h:outputLabel for="message">Meldungsüberschrift</h:outputLabel>
<h:inputTextarea id="message" value="#{resetBean.message}" />
<br/>
<h:commandButton action="#{resetBean.resetAction}"
value="Reset" immediate="true" onclick="resetForm()"/>
<h:commandButton action="#{resetBean.submitAction}" value="Submit" immediate="false"/>
</h:form>
</div>
<script type="text/javascript">
<!--//--><![CDATA[//><!--
var resetForm = function()
{
$("[id$='headline']").val(null)
$("[id$='message']").val(null)
}
var escapePressed = function()
{
resetForm();
resetByEscape();
}
$(document).keyup(function(e) {if (e.keyCode == 27) escapePressed();});
//--><!]]>
</script>
</html>
Here is the bean code:
package de.example.beans;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.validator.ValidatorException;
import org.apache.log4j.Logger;
#ViewScoped
#ManagedBean
public class ResetBean implements Serializable
{
private static final long serialVersionUID = 7282752623428425109L;
private static final Logger log = Logger.getLogger(ResetBean.class);
protected String headline = null;
protected String message = null;
public ResetBean() {
log.error("ResetBean");
}
#PostConstruct
public void postConstruct() {
log.error("postConstruct");
}
#PreDestroy
public void preDestroy() {
log.error("preDestroy");
}
public void resetAction() {
log.error("resetAction");
headline = null;
message = null;
}
public void submitAction() {
log.error("submitAction headline="+headline+" message="+message);
}
public void validateForm(ComponentSystemEvent event) throws ValidatorException {
log.error("validateForm");
}
public String getHeadline() {
return headline;
}
public void setHeadline(String headline) {
this.headline = headline;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Both the h:command button and the p:remoteCommand execute the same action in the same fashion. The difference is, that the h:command button responds to a mouse click, while the ESC key triggers the p:remoteCommand via javascript on using ESC key.
The problem is, that the route via p:remoteCommand seems to destroy the backing bean somehow (the bean is #ViewScoped). The #PreDestroy annotated method is never called, however: the next action on the page after using the p:remoteCommand forces the component to be created from scratch! Default constructor and #PostConstruct are called. Naturally some important parameters are missing now and the whole view gets shot to hell.
Any idea what is happening? Why the difference between p:remoteCommmand and h:commandButton in this instance? Any chance of working around the problem?
I could reproduce the problem. In my case and maybe the same case here (question provides only 'sample' code, not real one) it was caused by nested forms template->page.
If you have a ui:composition template or something similar to that, at the end of the generated HTML on client side it may creates nested forms like this:
<h:form>
...
<h:form>
...
</h:form>
...
</h:form>
which is invalid HTML code.
Remove unnecessary forms or reorganize code and test again. It should not call #postConstruct method when p:remoteCommand is called through JavaScript

Resources