valueChnageListner not working in jsf - jsf

I am new to jsf. I am implementing "valueChangeListener" in my canteen application. In backing bean I have a map of strings.
I have a dropdown in jsp page and when I select value from dropdown , listner is fired. I want to show corresponding value in text box. but its giving me "setting value == for null converter" error.
when i implemented converter, error changes and now its showing error that "Bean property is not writable".
I am using jsf 1.2. I have seen many posts regarding this but nothing worked.
plz guys help me.....Thanks in advance.
//jsp code
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%# taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%# taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<f:view>
<h:form id="myform">
<html>
<head>
<body>
<h:outputText value="select chinese" /><h:selectOneMenu id="chinese" value="#{mychinese.chineseName}" onchange="submit()">
<f:valueChangeListener type="backing_Bean.ChineseValueListner" />
<f:selectItems value="#{mychinese.chineseName}" />
</h:selectOneMenu>
<br>
<h:outputText value="Message from server" /><h:inputText value="#{mychinese.chinesemessage}" />
<h:message for="chinese"/>
<body>
<head>
<html>
</h:form>
<f:view>
// backing bean code is as follows
package backing_Bean;
import java.util.LinkedHashMap;
import java.util.Map;
public class MyChinese {
private static Map<String, String> chineseName;
private String chinesemessage="Select-Chinese";
static {
chineseName = new LinkedHashMap<String, String>();
chineseName.put("Select-Chinese", "Chinese");
chineseName.put("Manchurian", "Manchurian");
chineseName.put("Hakka", "Hakka");
chineseName.put("Sezvan", "Sezvan");
chineseName.put("Singapori", "Singapori");
}
public String getChinesemessage() {
return chinesemessage.toString();
}
public void setChinesemessage(String chinesemessage) {
this.chinesemessage = chinesemessage;
}
public Map<String, String> getChineseName() {
return chineseName;
}
public void setChineseName(Map<String, String> chineseName) {
MyChinese.chineseName = chineseName;
}
}
//Listener code
package backing_Bean;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ValueChangeEvent;
import javax.faces.event.ValueChangeListener;
public class ChineseValueListner implements ValueChangeListener{
public void processValueChange(ValueChangeEvent event)
throws AbortProcessingException {
MyChinese chinese = (MyChinese) FacesContext.getCurrentInstance()
.getExternalContext().getSessionMap().get("mychinese");
chinese.setChinesemessage(event.getNewValue().toString());
FacesMessage fm = new FacesMessage();
fm.setDetail(chinese.getChinesemessage());
}
}

The problem's that you're using a Map<String, String> to hold the selected value of your <h:selectOneMenu>:
<h:selectOneMenu id="chinese" value="#{mychinese.chineseName}" onchange="submit()">
...
</h:selectOneMenu>
In order to solve this, you should bind the value tag attribute to a String attribute in your managed bean.
MyChinese class modification:
public class MyChinese {
private static Map<String, String> chineseName;
private String chinesemessage="Select-Chinese";
private String selectedChineseName;
//the getter/setter functions for the new selectedChineseName attribute
//the rest of your code
}
JSP modification:
<h:selectOneMenu id="chinese" value="#{mychinese.selectedChineseName}"
onchange="submit()">
...
</h:selectOneMenu>
Note that by having this, maybe you won't need the valueChangeListener.
Note that you have problems in your HTML:
The <head> element must not wrap the <body> element, first you write the <head>, close it and then it comes the <body> and it's, uhm, body.
The <h:form> will generate a plain HTML <form>,so it must be inside the <body> tag, not outside.
The <h:form> should only contain the elements that will be sent in the request, no more elements, this in order to generate confusion with the values in the managed bean when repeated.
Fixing this code:
<f:view>
<html>
<head>
</head>
<body>
<h:form id="myform">
<h:outputText value="select chinese" />
<h:selectOneMenu id="chinese" value="#{mychinese.selectedChineseName}" onchange="submit()">
<f:valueChangeListener type="backing_Bean.ChineseValueListner" />
<f:selectItems value="#{mychinese.chineseName}" />
</h:selectOneMenu>
</h:form>
<br>
<h:outputText value="Message from server" />
<h:inputText value="#{mychinese.chinesemessage}" />
<h:message for="chinese"/>
</body>
</html>
<f:view>

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.

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

JSF adding textfields dynamically on click of a button

I have written the following code so that I can have a single textfield followed by a add button and a save button at the bottom.
I want the first textfield and add button to be fixed, but whenever a user cicks on add button, a text field gets added below the present textfield and the add button and save button goes down.
I have the following piece of code, but it doesnt seem to working.
<?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:c="http://java.sun.com/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Dashboard | BlueWhale Admin</title>
<link rel="stylesheet" type="text/css" href="../css/reset.css" media="screen" />
<link rel="stylesheet" type="text/css" href="../css/text.css" media="screen" />
<link rel="stylesheet" type="text/css" href="../css/grid.css" media="screen" />
<link rel="stylesheet" type="text/css" href="../css/layout.css" media="screen" />
<link rel="stylesheet" type="text/css" href="../css/nav.css" media="screen" />
</h:head>
<body>
<h:form>
<hr/>
<h:dataTable id="newsinputs" value="#{newsAlerts.values}" var="item" cellspacing="10">
<h:column>
<h:outputLabel value="#{item.label}" />
</h:column>
<h:column>
<h:inputText value="#{item.news}" size="100" /><br/>
</h:column>
</h:dataTable>
<h:commandButton styleClass="btn btn-blue" action="#{newsAlerts.add()}" value="Add"></h:commandButton>
<hr/>
<h:commandButton styleClass="btn btn-blue" action="#{newsAlerts.submit}" value="Save" />
</h:form>
</body>
</html>
The bean class is as follows
package com.kc.aop.bean;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import com.kc.aop.VO.NewsVO;
#ManagedBean(name = "newsAlerts")
#ViewScoped
public class News
{
private List<NewsVO> values;
public News()
{
this.values = new ArrayList<NewsVO>();
NewsVO newsVO = new NewsVO();
newsVO.setLabel("News "+ this.values.size()+1);
getValues().add(newsVO);
}
public String submit() {
for(NewsVO newsVO : this.values)
{
System.out.println(newsVO.getNews());
System.out.println(newsVO.getLabel());
}
return null;
// save values in database
}
public List<NewsVO> getValues() {
return values;
}
public void setValues(List<NewsVO> values) {
this.values = values;
}
public String add()
{
NewsVO newsVO = new NewsVO();
newsVO.setLabel("News "+ this.values.size()+1);
this.values.add(newsVO);
return "success";
}
}
You're returning non-null/void from action method:
public String add() {
// ...
return "success";
}
A non-null/void outcome creates a new view scope. You need to return null or void instead to keep the same view.
public String add() {
// ...
return null;
}
or
public void add() {
// ...
}
There's absolutely no need to change it by an action listener as suggested by the other answer. It serves a completely different purpose.
See also:
Recommended JSF 2.0 CRUD frameworks
You need to use actionListener or at least modify action to return void or null in your <h:commandButton /> since you stay in the same view. By using action with a return value, the ViewScope is broken and recreated.
View code :
<h:commandButton styleClass="btn btn-blue" actionListener="#{newsAlerts.add}" value="Add" />
<hr/>
<h:commandButton styleClass="btn btn-blue" actionListener="#{newsAlerts.submit}" value="Save" />
Bean code :
public void add(ActionEvent event)
{
NewsVO newsVO = new NewsVO();
newsVO.setLabel("News "+ this.values.size()+1);
this.values.add(newsVO);
}
public void submit(ActionEvent event)
{
for(NewsVO newsVO : this.values)
{
System.out.println(newsVO.getNews());
System.out.println(newsVO.getLabel());
}
}
More info :
Action vs ActionListener

jsf immediate="true" regarding binding to session bean

I have a listing page that goes to an add page. The add page has a name textbox whose value is bound to a session scoped bean.
The listing page has an add button that goes via an action method to the add page. This action method clears the object that the name textbox is bound to.
I also have a cancel button on the add page, which is bound to an action method that again clears the value that the name textbox is bound to.
If nothing is set to immediate, this all works fine.
However, if I set the cancel button to immediate, if I enter values in the name field, and then click cancel, the action method is fired and clears the object in the backing bean and goes to the listing page. If I then click add, the action method clears the object again (ignore if it's best method or not) and then goes to the add page. I would now expect the add page's name textbox to be empty, but it's not?! Surely, since the add button is not immediate, the values should be re-bound and empty?
Below is the relevant XHTML for the add button on the listing page
<h:commandButton id="addButton"
value="Add"
action="#{myBean.gotoAdd}"/>
Below is the relevant XHTML for the input box on the add page (myBean is session scoped), followed by that of the cancel button on the add page.:
<h:inputText id="newName"
value="#{myBean.newObject.name}"
binding="#{myBean.newNameInput}"
styleClass="name" />
<h:commandButton id="cancelButton"
value="Cancel" immediate="true"
action="#{myBean.cancelAdd}"
onclick="return confirm('You sure?');"/>
I almost never use the binding property of tags, except for when I need to identify which item of a list has had an action fired on it, so I am not particularly well-informed about its uses. But I know that without using binding your code would most likely work as you expected, so my expectation is that whatever javax.faces.component.UIxxx object you are binding to isn't getting reset correctly.
I'm having very similar problems right now.
Besides removing the binding and/or immediate attribute, try calling setSubmittedValue() on component with binding from action called upon click on 'add' button.
Alas, even if it helps you, you would still have to do it in any action that can lead to displaying same component after cancel.
That's why I'm still trying to figure out some better solution...
If you use immediate="true" then the value will be kept, this is how the parameter works. You should take a look at the following links:
http://wiki.apache.org/myfaces/How_The_Immediate_Attribute_Works
http://wiki.apache.org/myfaces/ClearInputComponents
Ok, here's an example that I did from scratch. I have two cancel buttons, one that is immediate, and one that isn't. Example of steps to reproduce:
Go to james-list page and click Add
The add page displays with empty fields. Enter values for all fields and click Add.
The listing page displays and is updated to include the new person. Click Add.
The add page displays with empty fields. Enter values for all fields and Click Cancel (Immediate)
The listing page displays and is unchanged. Click Add.
The add page displays however the fields are not empty as I would expect. Click Cancel.
The listing page displays and is unchanged. Click Add.
The add page displays and NOW the fields are not empty.
James.java:
package com.jamiebarrow;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.component.UIComponent;
#ManagedBean
#SessionScoped
public class James {
private UIComponent idComponent;
private UIComponent firstNameComponent;
private UIComponent lastNameComponent;
public UIComponent getIdComponent() {
return idComponent;
}
public void setIdComponent(UIComponent idComponent) {
this.idComponent = idComponent;
}
public UIComponent getFirstNameComponent() {
return firstNameComponent;
}
public void setFirstNameComponent(UIComponent firstNameComponent) {
this.firstNameComponent = firstNameComponent;
}
public UIComponent getLastNameComponent() {
return lastNameComponent;
}
public void setLastNameComponent(UIComponent lastNameComponent) {
this.lastNameComponent = lastNameComponent;
}
private List<Person> personResults;
private Person person;
public James() {
personResults = new ArrayList();
personResults.add(new PersonBuilder(1, "Bob", "Uncle").build());
personResults.add(new PersonBuilder(2, "Jack", "Black").build());
}
public List<Person> getPersonResults() {
return personResults;
}
public void setPersonResults(List<Person> personResults) {
this.personResults = personResults;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
private void clearPerson() {
person = new PersonBuilder().build();
}
public String gotoList() {
return "james-list";
}
public String gotoAdd() {
clearPerson();
return "james-add";
}
public String cancelAdd() {
clearPerson();
return gotoList();
}
public String addPerson() {
personResults.add(person);
return gotoList();
}
}
james-list.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-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>list page</title>
</h:head>
<body>
<div class="container">
<div class="content">
<h:messages showSummary="true" showDetail="false" errorClass="error" infoClass="info"
warnClass="warn"/>
<h:form>
<h:dataTable value="#{james.personResults}" var="person">
<h:column>
<f:facet name="header">Id</f:facet>
<h:outputText value="#{person.id}"/>
</h:column>
<h:column>
<f:facet name="header">Name</f:facet>
<h:outputText value="#{person.firstName}"/>
</h:column>
<h:column>
<f:facet name="header">Surname</f:facet>
<h:outputText value="#{person.lastName}"/>
</h:column>
</h:dataTable>
<h:panelGroup layout="block">
<h:commandButton value="Add" action="#{james.gotoAdd}"/>
</h:panelGroup>
</h:form>
</div>
</div>
<ui:debug hotkey="L" rendered="true"/>
</body>
</html>
james-add.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-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>add page</title>
</h:head>
<body>
<div class="container">
<div class="content">
<h:messages showSummary="true" showDetail="false" errorClass="error" infoClass="info"
warnClass="warn"/>
<h:form>
<fieldset>
<legend>Add Person</legend>
<h:panelGrid columns="2">
<h:outputLabel for="PersonId" value="Id:"/>
<h:inputText id="PersonId" value="#{james.person.id}" binding="#{james.idComponent}"/>
<h:outputLabel for="PersonFirstName" value="First Name:"/>
<h:inputText id="PersonFirstName" value="#{james.person.firstName}" binding="#{james.firstNameComponent}"/>
<h:outputLabel for="PersonLastName" value="Last Name:"/>
<h:inputText id="PersonLastName" value="#{james.person.lastName}" binding="#{james.lastNameComponent}"/>
</h:panelGrid>
<h:panelGroup layout="block">
<h:commandButton value="Add" action="#{james.addPerson}"/>
<h:commandButton value="Cancel (immediate)" action="#{james.cancelAdd}" immediate="true"/>
<h:commandButton value="Cancel" action="#{james.cancelAdd}"/>
</h:panelGroup>
</fieldset>
</h:form>
</div>
</div>
<ui:debug hotkey="L" rendered="true"/>
</body>
</html>

Resources