As you can see in the screenshot, I am having a JSF implicit value validation error for the property "member.city".
The purpose is to -through ajax - populate the city select One Menu after selecting a country on the previous Country Select one menu.
This is achieved by using selectOneMenu change listener and ajax to update the component displaying list of cities. However, I get a validation error and the form is not submitted.
I tried with Entities with and without (hascode and equals methods), but in vain.
I used a separated Managed Bean ViewScoped to retrive the filtered list, but in vain.
**
If I replace the filtered list of cities by the list that retrieves all
cities (in the xhtml form, replace <f:selectItems value="#{cityBean.citiesByCountry}" /> by <f:selectItems value="#{cityBean.all}" />, there's no validation error and the form successfully gets
submitted.
**
Here is the code:
Form:
<p:outputLabel for="country" value="#{i18n.country}" />
<p:selectOneMenu valueChangeListener="#{cityBean.selectCountry}" rendered="true" id="country" value="#{newMember.country}" converter="#{countryBean.converter}"
style="width:160px;text-align:left;border:thin solid gray;"
required="true" requiredMessage="#{i18n.required}">
<f:selectItems value="#{countryBean.all}" var="countryname" itemLabel="#{countryname.name}"/>
<p:ajax event="change" update="city" />
</p:selectOneMenu>
<p:message for="country" />
<p:outputLabel for="city" value="#{i18n.city}" />
<p:selectOneMenu rendered="true" id="city" value="#{newMember.city}" converter="#{cityBean.converter}" converterMessage="Conversion error!"
style="width:160px;text-align:left;border:thin solid gray;"
required="true" requiredMessage="#{i18n.required}">
<f:selectItems value="#{cityBean.citiesByCountry}" var="cityname" itemLabel="#{cityname.cityname}"/>
</p:selectOneMenu>
<p:message for="city" />
City Entity head:
#XmlRootElement
#Entity
#Table(name = "city", schema = "public")
#NamedQueries({
#NamedQuery(name = "City.findAll", query = "SELECT c FROM City c"),
#NamedQuery(name = "City.findById", query = "SELECT c FROM City c WHERE c.id = :id"),
#NamedQuery(name = "City.findByCountry", query = "SELECT c FROM City c WHERE c.country = :country"),
#NamedQuery(name = "City.findByCountryOrderedByName", query = "SELECT c FROM City c WHERE c.country = :country ORDER BY c.cityname ASC") })
#NamedNativeQueries({ #NamedNativeQuery(name = "City.findCountryNativeSQL", query = "select * from city c where c.countrybeta = :country.betacode", resultClass = City.class) })
public class City implements java.io.Serializable {
private static final long serialVersionUID = 3364735938266980295L;
private int id;
private Integer version;
private Country country;
private String cityname;
private String district;
private int population;
private Set<Member> members = new HashSet<Member>(0);
public City() {
}
// ...remainder of entity code (contructors and fields..)
The Bean:
#Named
#Stateful
#ConversationScoped
public class CityBean implements Serializable {
private static final long serialVersionUID = 1L;
private City city;
private List<City> cityList;
public City getCity() {
return this.city;
}
private Country selectedCountry;
#Inject
private Conversation conversation;
#PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;
// remainder of code....
// The List that works fine with Select one Menu
public List<City> getAll() {
CriteriaQuery<City> criteria = this.entityManager.getCriteriaBuilder()
.createQuery(City.class);
return this.entityManager.createQuery(
criteria.select(criteria.from(City.class))).getResultList();
}
#PostConstruct
public void init() {
setCityList(getCitiesByCountry());
}
public List<City> getCityList() {
return cityList;
}
public void setCityList(List<City> cityList) {
this.cityList = cityList;
}
/**
* The List That triggers a jsf value validation error
* #return List of Cities by Country ordered by city name
*/
public List<City> getCitiesByCountry() {
TypedQuery<City> query = this.entityManager.createNamedQuery(
"City.findByCountryOrderedByName", City.class);
query.setParameter("country", selectedCountry);
return query.getResultList();
}
// The Select One Menu Listener
public void selectCountry(ValueChangeEvent event) {
if (event != null) {
selectedCountry = (Country) event.getNewValue();
}
}
// getters and setters....
ENV:
- JSF 21
- Hibernate
- JBoss AS 7.1
- PrimeFaces 3.5
- Linux 3.5 / Firefox 18.0.2
Your concrete problem is caused because you aren't starting the conversation in #PostConstruct and thus the bean behaves like request scoped. This way the list of cities will incompatibly change during processing the form submit and become empty (and thus the selected item couldn't be found in the list of available items and hence this validation error).
You need to start the conversation in the #PostConstruct.
conversation.begin();
See also:
How to replace #ManagedBean / #ViewScope by CDI in JSF 2.0/2.1
Validation Error: Value is not valid
Unrelated to the concrete problem, using valueChangeListener and performing business logic in getter methods is the wrong approach. You should not be performing business logic in getter methods at all. This is plain inefficient. They should solely return already-prepared bean properties.
Rewrite your logic as follows:
<p:selectOneMenu value="#{bean.country}" ...>
<f:selectItems value="#{bean.countries}" />
<p:ajax listener="#{bean.updateCities}" update="city" />
</p:selectOneMenu>
<p:selectOneMenu id="city" value="#{bean.city}" ...>
<f:selectItems value="#{bean.cities}" />
</p:selectOneMenu>
with
private Country country;
private List<Country> countries;
private City city;
private List<City> cities;
#PostConstruct
public void init() {
countries = service.listCountries();
public void updateCities() {
cities = service.listCities(country);
}
// Add/generate normal!! getters/setters.
See also:
Why JSF calls getters multiple times
Our selectOneMenu tag wiki page
Related
I've two session scoped beans I need to pass values between them through f:setPropertyActionListener but I cant read it from receivable end.
<p:selectOneListbox style="height: 100%; width: 100%" id="lstSubject" required="true" requiredMessage="Please select any Subject"
value="#{chooseSubExamManagedBean.subId}" >
<f:selectItems value="#{chooseSubExamManagedBean.mapSubjects}" />
</p:selectOneListbox>
user chooses the subject and I've to pass this id from p:command button to another bean
<p:commandButton id="cmdProceed" value="Proceed" action="#{chooseSubExamManagedBean.gotoFillMarks}" >
<f:setPropertyActionListener target="#{fillMarksManagedBean.subId}" value="#{chooseSubExamManagedBean.subId}" />
</p:commandButton>
the managed bean fillMarksManagedBean
#Named(value = "fillMarksManagedBean")
#javax.enterprise.context.SessionScoped
public class FillMarksManagedBean implements Serializable{
private int SubId;
private String ExamDetail;
public void setSubId(int SubId) {
this.SubId = SubId;
}
public int getSubExamId() {
return SubExamId;
}
and use that subId in
#PostConstruct
public void init() {
ExamDetail = clsFillMarks.getExamDetail(SubId);
}
...
How do i do this?
Thanks in advance
I have 3 managebean one model and 2 controllers (1 for the popup text) i want a popup after i insert into the database.
my page is like this the problem is that when i call for mensaje.mostrar() i works but when i try to call cursoControlador.registrarCurso() and from there try to call mensaje.mostrar() that changes the value from mostrarMensaje (boolean) don't show the popup.
<ui:define name="centro">
<h:form>
<h:panelGrid columns="3" cellpadding="5">
<p:outputLabel value="Nombre" />
<p:inputText value="#{cursoModelo.nombre}"/>
this is the button use and works fine
<p:commandButton action="#{mesaje.mostrar()}" value="Registrar Curso" >
<f:ajax render="#form"/>
</p:commandButton>
and this is the behavior i want
<p:commandButton action="#{cursoControlador.registrarCurso()}" value="Registrar Curso" >
<f:ajax render="#form"/>
</p:commandButton>
and this is the popup message i want to show
</h:panelGrid>
<h:panelGroup layout="block" styleClass="fondo-popup" rendered="#{mensaje.mostrarMensaje}">
<div class="panel-popup">
<p:outputLabel value="#{mensaje.texto}"/>
<h:commandButton value="Aceptar" action="#{mensaje.esconder()}">
<f:ajax render="#form"/>
</h:commandButton>
</div>
</h:panelGroup>
</h:form>
</ui:define>
model
#Named(value = "cursoModelo")
#SessionScoped
public class CursoModelo implements Serializable {
private String nombre;
//getters and setters...
}
controller 1
#Named(value = "cursoControlador")
#SessionScoped
public class CursoControlador implements Serializable{
#Inject private CursoModelo cursoModelo;
#Inject private Mensaje mensaje;
/**
* Creates a new instance of CursoControlador
*/
public CursoControlador() {
}
public String registrarCurso(){
//SOME CODE that inserts into de database
mensaje.mostrar(); //this is the problem probably i'm doing it wrong
return "index";
}
}
controller 2 (The controller for the message)
#Named(value = "mensaje")
#SessionScoped
public class Mensaje implements Serializable {
private String texto;
private boolean mostrarMensaje;
/**
* Creates a new instance of Mensaje
*/
public Mensaje() {
texto = "Mensaje a mostrar";
mostrarMensaje = false;
}
public void mostrar(){
mostrarMensaje = true;
}
public void esconder(){
mostrarMensaje = false;
}
//getters and setters from texto and mostrarMensaje
}
I am learning JavaEE and I am playing around with ajax call with jsf and managedbean. I am trying to display the text as soon as i change the value from the drop down list. I see many people have the same problem on stackoverflow and i try to follow answers that are marked as accepted but I still can't make it work. Can someone please tell me where my error is?
Here is the jsf code:
<h:form>
<h:selectOneMenu id="productlist" value="#{productRepoMB.selectedProduct}">
<f:selectItems value="#{productRepoMB.productList}" var="product" itemValue="#{product.productID}" />
<f:ajax event="valueChange"
render="result"
listener="#{productRepoMB.selectMenuListener}" />
</h:selectOneMenu>
text changed: <h:outputText id="result" value="#{productRepoMB.text}" />
</h:form>
Here is managed bean code, Products list is populated from a database:
#Named
#RequestScoped
public class ProductRepoMB implements Serializable {
#EJB
private ProductsRepo productRepo;
private Products selectedProduct;
private List<Products> productList;
private String text="init text"; //use for testing ajax call
public ProductRepoMB() {
}
public Products getSelectedProduct() {
return selectedProduct;
}
public List<Products> getProductList() {
productList = productRepo.findAll();
return productList;
}
//The following code are used to testing ajax only!
public void selectMenuListener(AjaxBehaviorEvent e) {
setText("changed!");
}
public String getText() {
return text;
}
public void setText(String text){
this.text = text;
}
}
I have a form like this:
<h:form>
Phone number:
<h:inputText id="phone_number"
value="#{dbUserManager.phoneNumber}"
validatorMessage="The phone number is invalid."
required="#{auth.value eq 'MOBILE'}"
requiredMessage="Phone number is required." />
</h:inputText>
Authentication type:
<h:selectOneMenu value="#{dbUserManager.authentication}" converter="#{authenticationTypeConverter}" binding="#{auth}">
<f:selectItems value="#{dbUserManager.authTypeList}" />
</h:selectOneMenu>
</h:form>
AuthenticationType is an entity similar to this:
#Entity
public class AuthenticationType implements Serializable
{
#Id
#Basic(optional = false)
private Short id;
#Basic(optional = false)
private String description;
#Override
//...
public String toString()
{
return description;
}
and finally AuthenticationTypeConverter:
#Stateless
#ManagedBean
#FacesConverter(value="authenticationTypesConverter")
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class AuthenticationTypeConverter implements Converter
{
#PersistenceContext(unitName="pu")
private EntityManager em = null;
#Override
public Object getAsObject(FacesContext fc, UIComponent uic, String string)
{
TypedQuery<AuthenticationType> q = em.createNamedQuery(
AuthenticationType.FIND_BY_DESCRIPTION,
AuthenticationType.class);
q.setParameter("description", string);
return q.getSingleResult();
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object o)
{
if (o == null)
{
return "";
}
return o.toString();
}
}
What I tried to do is that to set the required of phone number to true when authentication type is set to 'MOBILE'. But it's not behaving as I expect.
I think the problem lies in the fact that I need to use FacesConverter for AuthenticationType. But I don't know how to solve it.
Can anyone give a hint?
Thanks
You have to rerender the h:inputText-field after the user chose from your h:selectOneMenu. To do so, change this selection to
<h:selectOneMenu value="#{dbUserManager.authentication}"
converter="#{authenticationTypeConverter}" binding="#{auth}">
<f:selectItems value="#{dbUserManager.authTypeList}" />
<f:ajax event="change" render="phone_number" />
</h:selectOneMenu>
Also in the inputTexts required-attribute I would expect something more like
{dbUserManager.authentication.description}
Give it a try...
Update 2014/01/22:
If you want to hold already typed informations in the phone_number field, you can tell the <f:ajax> tag to execute not only selectOneMenu but also the input field before rendering it new. In this case replace the upper <f:ajax /> solution with
...
<f:ajax event="change" execute="#this phone_number" render="phone_number" />
...
I have 2 SelectOneMenu as follows in the index.xhtml. The menu1 essentially chooses a language(sp or en) and menu2 displays the possible serial numbers(0 to 3). I have the init constructor(post constructor) which initialises the default values on the two Menus. However for some strange reason, if I select a serial number other than the default serial number for the language other than the default language, somehow the language gets reset to init default :(
<?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:f="http://java.sun.com/jsf/core">
<h:head>
<title>My page</title>
</h:head>
<h:body>
<div>
<h4>Change Existing Description</h4>
</div>
<h:form id="myForm">
<h:panelGrid columns="4">
<h:outputLabel value="Language:" />
<h:selectOneMenu value="#{myBean.language}">
<f:selectItems value="#{myBean.languages}" />
<f:ajax listener="#{myBean.doUpdate}" render ="myForm" />
</h:selectOneMenu>
<h:outputLabel value="SerialID:" />
<h:selectOneMenu value="#{myBean.serialID}">
<f:selectItems value="#{myBean.serialIDs}" />
<f:ajax listener="#{myBean.doUpdate}" render ="myForm" />
</h:selectOneMenu>
</h:panelGrid>
</h:form>
</h:body>
</html>
Here is my Bean code. Where is the problem?? please advise!
package bean;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.Stateful;
import javax.enterprise.context.RequestScoped;
import javax.faces.bean.ManagedBean;
#ManagedBean(name = "myBean")
//#Stateless
#Stateful
#RequestScoped
public class MyBean {
public static final int PERMISSIONS = 2;
private List<String> languages;
private String language;
private int serialID;
private List<Integer> serialIDs;
/**
* init() method for initializing the bean. Is called after constuction.
*/
#PostConstruct
private void init() {
//public MyBean () {
languages = getAllLanguages();
language = "en"; //defaultLanguage
serialID = 3;
serialIDs = getSerialIDsFromOverview();
}
public List<String> getLanguages() {
System.out.println("getLanguages, language " +language);
return languages;
}
public int getPERMISSIONS() {
return PERMISSIONS;
}
public String getLanguage() {
System.out.println("getLanguage " +language);
return language;
}
public void setLanguage(String language) {
System.out.println("setLanguage " +language);
this.language = language;
}
public int getSerialID() {
System.out.println("getSerialID " +serialID);
return serialID;
}
public void setSerialID(int serialID) {
System.out.println("setSerialID " +serialID);
this.serialID = serialID;
}
public List<Integer> getSerialIDs() {
System.out.println("getSerialIDs language = "+language );
return serialIDs;
}
public List<String> getAllLanguages() {
List<String> results = new ArrayList<String>();
results.add("sp");
results.add("en");
if(results != null){
System.out.println("getting all languages");
}
return results;
}
public void doUpdate() {
System.out.println("doUpdate language " +language);
System.out.println("doUpdate serialID " +serialID);
}
/**
* Returns a list of all serialIDs present in the overview.
* #return
*/
private List<Integer> getSerialIDsFromOverview() {
List<Integer> results = new ArrayList<Integer>();
results.add(0);
results.add(1);
results.add(2);
results.add(3);
return results;
}
}
UPDATES:
After taking suggestions from cubbuk, I sat down and corrected my code with #ViewScoped annotation and making the bean implement Serializable. THIS WORKS. However, the next thing I had to do was include an #EJB annotation to call a stateless bean which calls the Entity manager to fetch the serialIDs from a database instead of "hardcoding" it. That is when I encounter the problem: Not serializable exception "java.io.NotSerializableException: bean.__EJB31_Generated__. How do I solve this? When I made myBean back to RequestScope and remove Serializable, I could run the code without problems however there the toggling of the menu to init values :(
By the way I check this post: #EJB in #ViewScoped managed bean causes java.io.NotSerializableException and set my STATE SAVING METHOD to server but that gives me "empy response from server" pop up message :(
Please help!
Since you are using #RequestScoped bean as your backing bean after each request your init method is getting called and your values are getting reset. To avoid that you need to use #ViewScoped bean as your backing bean. I updated your bean accordingly note that your backing bean now implements Serializable interface. This is needed as this bean will be stored in your servlet and it needs to be flushed to disk if the content can not be hold in the memory. For learning the details of #ViewScoped beans please check the following post:
http://balusc.blogspot.com/2010/06/benefits-and-pitfalls-of-viewscoped.html
Apart from these, for naming conventions I renamed your getAllLanguages and getSerialIDsFromOverview methods to initAllLanguages and initSerialIds as methods starting with get and set can be confusing because they are mostly used for getters and setters.
Lastly when you use f:ajax command by default the UIInput the ajax command is bind to is rendered and executed. Since you don't refresh the h:selectOneMenu menus according to the values of each other you don't need to render the whole form. The following will be enough for this case:
<h:form id="myForm">
<h:panelGrid columns="4">
<h:outputLabel value="Language:" />
<h:selectOneMenu value="#{myBean.language}">
<f:selectItems value="#{myBean.languages}" />
<f:ajax listener="#{myBean.doUpdate}"/>
</h:selectOneMenu>
<h:outputLabel value="SerialID:" />
<h:selectOneMenu value="#{myBean.serialID}">
<f:selectItems value="#{myBean.serialIDs}" />
<f:ajax listener="#{myBean.doUpdate}"/>
</h:selectOneMenu>
</h:panelGrid>
</h:form>
#ManagedBean
#ViewScoped
public class MyBean implements Serializable
{
public static final int PERMISSIONS = 2;
private List<String> languages;
private String language;
private int serialID;
private List<Integer> serialIDs;
/**
* init() method for initializing the bean. Is called after constuction.
*/
#PostConstruct
protected void init()
{
//public MyBean () {
System.out.println("lang: " + language);
System.out.println("serialId: " + serialID);
System.out.println("init is called");
initAllLanguages();
initSerialIds();
language = "en"; //defaultLanguage
serialID = 3;
}
public List<String> getLanguages()
{
return languages;
}
public int getPERMISSIONS()
{
return PERMISSIONS;
}
public String getLanguage()
{
return language;
}
public void setLanguage(String language)
{
this.language = language;
}
public int getSerialID()
{
return serialID;
}
public void setSerialID(int serialID)
{
this.serialID = serialID;
}
public List<Integer> getSerialIDs()
{
return serialIDs;
}
private void initAllLanguages()
{
languages = new ArrayList<String>();
languages.add("sp");
languages.add("en");
}
public void doUpdate()
{
System.out.println("doUpdate language " + language);
System.out.println("doUpdate serialID " + serialID);
}
/**
* Returns a list of all serialIDs present in the overview.
*
* #return
*/
private void initSerialIds()
{
serialIDs = new ArrayList<Integer>();
serialIDs.add(0);
serialIDs.add(1);
serialIDs.add(2);
serialIDs.add(3);
}
}
Cheers