How to execute managed bean method on selectOneMenu change? - jsf

I have the following Managed Bean:
import javax.faces.bean.ManagedBean;
#ManagedBean
public class MyBean {
public void mostrarCentroSeleccionado() {
System.out.println("Value changed");
}
}
And inside my .xhtml file the following selectOneMenu:
<p:selectOneMenu value="#{MyBean.centros.idcentro}" >
<p:ajax event="change" listener="#{MyBean.mostrarCentroSeleccionado}" />
<f:selectItem itemLabel="Seleccione un centro" itemValue="" />
<f:selectItems value="#{MyBean.centros}" />
</p:selectOneMenu>
When I run that code I get the following exception:
javax.el.MethodNotFoundException
Thanks in advance

If Holger's solutions works out, its fine.
BUT: It is horrible to start start a Java Class Name with lower case letter. You can start with a capital letter and JSF will manage it for you, so you can still use
listener="#{myBean.mostrarCentroSeleccionado()}"
If this does not meet your requirements you can use
#ManagedBean(name = "myBean ")
Instead of myBean you can choose what ever you want.

The problem was in the tag:
<p:ajax listener="#{MyBean.function()}"/>
The function must have "()" becouse I´m not taking the event.

Related

can't access to suffixs or enum's values in primefaces <p:selectOneMenu component.. any solution?

Hi I am currently working on a java project (jsf) with primefaces and I am using enum, but I cannot access its values from the view with primefaces. I have temporarily solved the problem by creating a getter from the Bean and accessing the enum values, but it should work with allSuffix = "ALL_ENUM_VALUES" or ALL_VALUES by default, I don't know if it's a problem with primefaces, joinfaces or something I'm missing. I have looked into the official documentation and it should work... any solution?
my code is
<p:importEnum
type="com.path.enumeration.AltoMedioBajo"
var="AltoMedioBajo"
allSuffix="ALL_ENUM_VALUES" />
<p:outputLabel
for="posibilidad"
value="#{informe_msg.posibilidad}" />
<p:selectOneMenu
id="posibilidad"
style="width: 150px"
value="#{informeSeguimientoDto.specification.posibilidad}">
<f:selectItem
itemLabel=""
itemValue="" />
<f:selectItems
value="#{AltoMedioBajo.ALL_ENUM_VALUES}"
var="posibilidad"
itemValue="#{posibilidad}"
itemLabel="#{peticion_msg[posibilidad.femKey]}" />
</p:selectOneMenu> ```
Hi this question was answered here: How to use enum values in f:selectItem(s)
With joinfaces I tested this example:
User Bean
#Named
#ApplicationScoped
public class UserBean {
public Role[] getRoles() {
return Role.values();
}
}
add_user.xhtml
<p:selectOneMenu id="roleId" value="#{userBean.newUser.roleId}">
<f:selectItem itemValue="" itemLabel=""/>
<f:selectItems value="#{userBean.roles}" var="role" itemValue="#{role.getId()}" itemLabel="#{messages['role_' += role]}"/>
</p:selectOneMenu>
Role Enum with custom order, it's not mandatory you can use default .ordinal() value
public enum Role {
ASSISTANT(1),
ACCOUNTANT(4),
CASHIER(5),
ADMIN(10);
private final int id;
Role(int id) {
this.id = id;
}
public int getId() {
return id;
}
// method to get the Role using Id from the database
public static Role valueOf(int id) {
return Arrays.stream(values())
.filter(role -> role.id == id)
.findFirst()
.orElse(null);
}}
messages_es.properties as Resource Bundle
role_ASSISTANT=Asistente
role_ACCOUNTANT=Contador
role_CASHIER=Cajero
role_ADMIN=Administrador
As per documentation/demo, you should use a repeat tag.
Edited: Try this version:
<p:importEnum type="com.path.enumeration.AltoMedioBajo" var="AltoMedioBajo"
allSuffix="ALL_ENUM_VALUES" />
<p:outputLabel for="posibilidad" value="#{informe_msg.posibilidad}" />
<p:selectOneMenu id="posibilidad" style="width: 150px"
value="#{informeSeguimientoDto.specification.posibilidad}">
<f:selectItem />
<ui:repeat var="posibilidad" value="#{AltoMedioBajo.ALL_ENUM_VALUES}">
<f:selectItem itemValue="#{posibilidad}"
itemLabel="#{peticion_msg[posibilidad.femKey]}"
</ui:repeat>

FacesComponent works in one page but doesn't in others (retrieves null from ajax event)

I don't know if there's a solved question for that. If so, I wasn't able to find it.
I'm creating a composite component with two SelectOneMenu that fires an event.
The thing is that this component works in one jsf but doesn't in others.
The component is inside three different xhtml. In all of them the event is fired when I change the value of the first SelectOneMenu, but only in one of the xhtml the value of the SelectItem is not null. In the rest of them, the retrieved value is "null"
//In p001DatosNotificacion.xhtml, it retrieves the selected value of the selectonemenu (b, for example)
//In the others it retrieves null
UISelectOne oneVoewl = (UISelectOne)event.getSource();
System.out.println("One Voewl > " + oneVoewl.getValue());
Can anyone help me and tell me where I'm making the mistake(s)?
Thanks in advance!
The code
Component backing bean
#FacesComponent(value="letterExample")
public class LetterExample extends UINamingContainer{
public void voewlAjaxListener(AjaxBehaviorEvent event){
UISelectOne oneVoewl = (UISelectOne)event.getSource();
System.out.println("One Voewl > " + oneVoewl.getValue());
}
Composite component (Note: I'm using an existing bean for testing)
<cc:interface componentType="letterExample" >
<cc:attribute name="bean" type="es.ccasa.sgnx.business.bean.Direccion" />
</cc:interface>
<cc:implementation>
<p:selectOneMenu id="oneMenuVoewl" value="#{cc.attrs.bean.codigoPais}"
binding="#{cc.uiSelectOneVoewl}" >
<f:selectItem itemLabel="Aaaa" itemValue="a" />
<f:selectItem itemLabel="Eeee" itemValue="e" />
<f:selectItem itemLabel="Iiii" itemValue="i" />
<f:selectItem itemLabel="Oooo" itemValue="o" />
<f:selectItem itemLabel="Uuuu" itemValue="u" />
<p:ajax event="change" listener="#{cc.voewlAjaxListener}" update="consonantWrapper" />
</p:selectOneMenu>
<h:panelGroup id="consonantWrapper" layout="block">
<p:selectOneMenu id="oneMenuConsonant" value="#{cc.attrs.bean.codigoProvincia}"
binding="#{cc.uiSelectOneConsonant}">
<f:selectItem itemLabel="Bbbb" itemValue="b" />
<f:selectItem itemLabel="Cccc" itemValue="c" />
<f:selectItem itemLabel="Dddd" itemValue="d" />
</p:selectOneMenu>
</h:panelGroup>
</cc:implementation>
Bean
public class Direccion implements Serializable {
private String codigoPais; /* with its getter and setter*/
private String codigoProvincia; /* with its getter and setter*/
}
XHTML
This is the way I use inside the xhtml pages: (The name of the controller changes depends on the current controller)
<sgnx:letter-example bean="#{controller.direccion}" />
The #Named beans
#Named
#ViewScoped
public class P001DatosNotificacionController
private Direccion direccion; /* with its getter and setter*/
#Named
#ViewScoped
public class P001GestionNotificacionesController
private Direccion direccion; /* with its getter and setter*/
#Named
#ViewScoped
public class P002BandejaProvisionalNotificacionesController
private Direccion direccion; /* with its getter and setter*/
After a few weeks I went back to the problem.
I decided to start again from scratch.
When I started to write the controller code and annotated it with #ViewScoped I realize about javax.faces.bean and javax.faces.view packages
And that was the mistake. I was using a wrong combination:
import javax.inject.Named;
import javax.faces.bean.ViewScoped;
So, the solution is as easy as using the proper combination of packages:
import javax.inject.Named;
import javax.faces.view.ViewScoped;
In these posts are the answer and the explanation:
#ViewScoped bean recreated on every postback request when using JSF 2.2
ManagedProperty in CDI #Named bean returns null
Inject CDI bean into JSF #ViewScoped bean

#ConversationScoped is spoiling the filtering and sorting options in form, #ViewScoped works fine

I'm working on a small course passing project, and I have a problem.
The manager.xhtml is a JSF page, it is used to view the data from database, sort them, filter them, delete entries and edit those entries. When I'm using #ViewScoped in Manager.java - everything EXCEPT the edit part works just fine. The "Edit" link is sending the user to another page - edit.xhtml. After I used #ConversationScoped to be able to read data send from manager.xhml in edit.xhtml. After using #ConversationScoped the entry editing option worked flawlessly, but it started making errors in some of the filtering/sorting options - sorting by CATEGORY started pulling out errors like "Name is null", filtering by price - the same.
Here is the code.
manager.xhtml
Here is the form in which the problems start to occur while using #ConversationScoped
<h:form>
<h:panelGrid id="filterPanel" columns="7">
<f:ajax render="filterValue" event="change" execute="filterValue">
#{text.sort}
<h:selectOneMenu value="#{manager.order}">
<f:selectItem itemValue="cargoName" itemLabel="#{text.cargo_name}"/>
<f:selectItem itemValue="price" itemLabel="#{text.cargo_price}"/>
<f:selectItem itemValue="category" itemLabel="#{text.cargo_category}"/>
</h:selectOneMenu>
<h:selectOneMenu id="filterType" value="#{manager.filterType}">
<f:selectItem itemValue="CARGO_NAME" itemLabel="#{text.cargo_name}"/>
<f:selectItem itemValue="PRICE" itemLabel="#{text.cargo_price_filter}"/>
<f:selectItem itemValue="CATEGORY" itemLabel="#{text.cargo_category}"/>
</h:selectOneMenu>
<h:panelGroup id="filterValue">
<h:panelGroup id="filterValues">
<h:inputText id="filterValueInput" value="#{manager.filterValue}" rendered="#{manager.filterType == 'CARGO_NAME'
or manager.filterType == 'PRICE'}"
required="#{manager.filterType == 'PRICE'}"/>
<h:message for="filterValueInput"/>
<h:inputText id="filterValueInput2" value="#{manager.filterValue2}" rendered="#{manager.filterType == 'PRICE'}"
required="#{manager.filterType == 'PRICE'}"/>
<h:message for="filterValueInput2"/>
</h:panelGroup>
<h:selectOneMenu id="cargoForm" value="#{manager.filterValue}" rendered="#{manager.filterType == 'CATEGORY'}">
<f:selectItem itemLabel="#{text.cargo_text_BOOKS}" itemValue="BOOKS"/>
<f:selectItem itemLabel="#{text.cargo_text_CALENDARS}" itemValue="CALENDARS"/>
<f:selectItem itemLabel="#{text.cargo_text_CD}" itemValue="CD"/>
<f:selectItem itemLabel="#{text.cargo_text_EBOOKS}" itemValue="EBOOKS"/>
<f:selectItem itemLabel="#{text.cargo_text_OFFICE}" itemValue="OFFICE"/>
<f:selectItem itemLabel="#{text.cargo_text_VINYL}" itemValue="VINYL"/>
</h:selectOneMenu>
</h:panelGroup>
</f:ajax>
<h:commandButton action="#{manager.filter}" value="#{text.button_refresh}"/>
<h:commandButton action="#{manager.reset}" value="#{text.button_reset}"/>
</h:panelGrid>
edit.xhtml
The edition form - it's filled with the data of selected entry ONLY when using #ConversationScoped:
Getting the ID sent by manager.xhtml
<h:inputHidden value="#{manager.editCargo.id}"/>
In the form the data is taken from manager like this:
<h:inputText id="cargoName" value="#{manager.editCargo.cargoName}" required="true">
</h:inputText>
button to save changes:
<h:commandButton value="#{text.edit_button}" action="#{manager.update}"/>
Manager.java - unnecesary code removed.
#ConversationScoped
#ManagedBean
public class Manager implements Serializable {
#Inject
private CargoRepository repository; // tworzy nową instancję objektu CargoRepository
private List<Cargo> cargos; // tworzy listę obiektów Cargo
private String order = CARGO_NAME; // musi istnieć by zainicjować jakąś zmienną order, ponieważ manager.xhtml już na starcie sortuje po order więc nie może być null.
private FilterType filterType = FilterType.CARGO_NAME;
private String filterValue;
private String filterValue2;
#Inject
private Conversation conversation;
Getters and setters removed...
#PostConstruct
public void init() {
cargos = repository.getAll(order);
editCargo = new Cargo();
}
public void filter() {
if (filterType == FilterType.PRICE) {
cargos = repository.getAll(filterType, filterValue, filterValue2, order);
} else {
cargos = repository.getAll(filterType, filterValue, order);
}
}
public void resetFilterValue() {
filterValue = "";
filterValue2 = "";
}
public String edit(Cargo cargo) {
conversation.start();
editCargo = cargo;
return "edit";
}
public String update() {
conversation.end();
repository.update(editCargo);
System.out.println(editCargo.toString());
init();
return "manager";
}
}
I've managed to repair the problem.
Instead of:
#ConversationScoped
#ManagedBean
I have used
#Named
#SessionScoped
The #SessionScoped was imported from
import javax.enterprise.context.SessionScoped;
I removed EVERYTHING related to #ConversationScoped including
#Inject
private Conversation conversation;
and every usage of
conversation.start();
conversation.end();
Everything is working flawlessly now.

primefaces selectOneMenu how to reload

I use 3 selectOneMenu components in my project. I need to reload content of the second after change in the first. Here are some parts of the files
index.xhtml
<h:form id="form">
<p:selectOneMenu id="Rząd" value="#{birdSelectorBean.selectedState}" effect="fade"
style="width: 150px;">
<f:selectItem itemLabel="Rząd" itemValue="" />
<f:selectItems value="#{birdSelectorBean.rzad}" />
<p:ajax render="#form" listener="#{birdSelectorBean.stateChangeListener}" />
</p:selectOneMenu>
<p:selectOneMenu id="rodzina" value="#{birdSelectorBean.selectedState}" effect="fade"
style="width: 150px;">
<f:selectItem itemLabel="Rodzina" itemValue="" />
<f:selectItems value="#{birdSelectorBean.rodzina}" />
</p:selectOneMenu>
<p:selectOneMenu id="rodzaj" value="#{birdSelectorBean.selectedState}" effect="fade"
style="width: 150px;">
<f:selectItem itemLabel="Rodzaj" itemValue="" />
<f:selectItems value="#{birdSelectorBean.rodzaj}" />
</p:selectOneMenu>
</h:form>
BirdSelectionBean.java:
public class BirdSelectorBean
{
private String selectedState;
private List<SelectItem> rzad;
private List<SelectItem> rodzina;
private List<SelectItem> rodzaj;
public BirdSelectorBean()
{
rzad = new ArrayList<>();
rzad.add(new SelectItem("Rząd_X"));
rzad.add(new SelectItem("Rząd_Y"));
rzad.add(new SelectItem("Rząd_Z"));
rodzina = new ArrayList<>();
rodzaj = new ArrayList<>();
}
public void stateChangeListener(ValueChangeEvent event)
{
rodzina.clear();
rodzina.add(new SelectItem("Rodzina_A"));
rodzina.add(new SelectItem("Rodzina_B"));
rodzina.add(new SelectItem("Rodzina_C"));
}
...
getters and setters
...
}
I read many topics on that but it doesn't work for me. I tried update="rodzina" like it is in example
here
and render option like it is said in that
topic:
But it still doesn't work. Please help me :]
In the p:ajax tag change render="#form" to update="#form". Render is used by f:ajax, primefaces use another name for some reason - see here.
Looks like your stateChangeListener method nevers get called and more important, your managed bean looks like hasn't any scope (at least from your question content), remember that it must be at least #ViewScoped in order to make this work. Also, another problem in your code is that you're using the same attribute to select the data for the three <p:selectOnuMenu> (which is not a problem yet since you haven't achieved what you wanted to begin with).
To make the ajax update work, remove the parameter from your stateChangeListener. Also let's add the other two attributes for the selected items from the dropdownlists.
#ManagedBean
#ViewScoped
public class BirdSelectorBean {
private String selectedState;
private String selectedStateRodzina;
private String selectedStateRodzaj;
//other fields and methods...
public void stateChangeListener() {
rodzina.clear();
rodzina.add(new SelectItem("Rodzina_A"));
rodzina.add(new SelectItem("Rodzina_B"));
rodzina.add(new SelectItem("Rodzina_C"));
}
}
And then update your desired <p:selectOneMenu> in your <p:ajax> call (I removed the non-directly related to the problem attributes from the components like style):
<p:selectOneMenu id="Rząd" value="#{birdSelectorBean.selectedState}">
<f:selectItem itemLabel="Rząd" itemValue="" />
<f:selectItems value="#{birdSelectorBean.rzad}" />
<p:ajax update="rodzina" listener="#{birdSelectorBean.stateChangeListener}" />
</p:selectOneMenu>
<p:selectOneMenu id="rodzina" value="#{birdSelectorBean.selectedStateRodzina}">
<f:selectItem itemLabel="Rodzina" itemValue="" />
<f:selectItems value="#{birdSelectorBean.rodzina}" />
</p:selectOneMenu>

Language switcher implementation in JSF

I have a complex jsf page with some widgets developed in PrimeFaces. Up to now, the application is completely ajaxified, meaning that there aren't submits, but all the events and updates are handled through Ajax behavior (this is not a must, but a nice-to-have feature). I have also done a SelectOneMenu for switching the language:
<h:form>
<p:panelGrid columns="2" >
<h:outputText value="#{msgs.SelectLanguage}" />
<p:selectOneMenu value="#{languageSwitcher.selectedLanguage}" >
<f:selectItems value="#{languageSwitcher.languages}" ></f:selectItems>
</p:selectOneMenu>
</p:panelGrid>
</h:form>
The switcher works well.
My problem is how to reload the translated messages when a language is selected.
I have tried these options:
Option 1
With an ajax update inside the selectOneMenu:
<p:ajax update="myFormsTobeUpdated" ></p:ajax>
This works great, and is the preferred solution because it's Ajax, but
EDITED
this solution doesn't ajax-update the Tab titles in the PrimeFaces TabView, and this is problem is blocking because the Tab titles need to be translated.
Option 2
With a complete reload of the page in Javascript. I have tried this but doesn't work (can't tell why):
<p:selectOneMenu value="#{languageSwitcher.selectedLanguage}" onchange="window.location.reload()" >
Option 3
With a complete reload of the page in Java like explained here: https://stackoverflow.com/a/1821708/870122 (to be honest I haven't tried it yet, but will do soon!)
Any suggestions are welcome.
If you're using at least PrimeFaces 3.2, then you can use
<p:ajax update="#all" />
to update the entire view. Before this version, the #all wasn't supported.
In your Form:
<h:selectOneRadio value="#{localeBean.language}"
onchange="submit()">
<f:selectItems value="#{collection.listLangs()}" var="s"
itemLabel="${s.description}" itemValue="${s.code}" />
</h:selectOneRadio>
but your not have a collection (REMEMBER, IN YOUR FORM):
<h:selectOneMenu value="#{localeBean.language}"
onchange="submit()">
<f:selectItem itemValue="en" itemLabel="English" />
<f:selectItem itemValue="es" itemLabel="Español" />
</h:selectOneMenu>
IN Primefaces, use this: p:selectOneMenu
In your Bean:
import java.lang.invoke.MethodHandles;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
#ManagedBean
#SessionScoped
public class LocaleBean {
private static final Logger LOG = LogManager.getLogger(MethodHandles.lookup().lookupClass());
private Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
public Locale getLocale() {
return locale;
}
public String getLanguage() {
return locale.getLanguage();
}
public void setLanguage(String language) {
LOG.info("Vamos a Cambiar a: " + language);
locale = new Locale(language);
LOG.info("Vamos a Cambiar a: " + locale.getDisplayName() + FacesContext.getCurrentInstance().getViewRoot());
FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
}
}
Since with Option 1 it's not possible to ajax-update the Tab titles in the PrimeFaces TabView, I have switched to Option 2, a complete reload of the page using JavaScript.
The code that makes it work is:
<h:form id="selectLanguage">
<p:panelGrid columns="2">
<h:outputText value="#{msgs.SelectLanguage}" />
<p:selectOneMenu value="#{languageSwitcher.selectedLanguage}" onchange="document.getElementById('selectLanguage').submit();" >
<f:selectItems value="#{languageSwitcher.languages}" ></f:selectItems>
</p:selectOneMenu>
</p:panelGrid>
</h:form>

Resources