Primefaces f:selectItems breaks button action [duplicate] - jsf

This question already has answers here:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
(12 answers)
Validation Error: Value is not valid
(3 answers)
How to populate options of h:selectOneMenu from database?
(5 answers)
Keep p:dialog open when a validation error occurs after submit
(6 answers)
Closed 1 year ago.
I'm making a simple program, where I try to open a dialog, set variables inside of it, then click a button at the bottom to make a new object.
<p:dialog header="Add a book" widgetVar="dlg" modal="true">
<h:outputText value="Title: "/>
<p:inputText label="Title: " value="#{bookController.title}" /><br/>
...
<p:selectCheckboxMenu title="Author(s)" value="#{bookController.authors}" label="Author(s)" style="min-width: 15rem" multiple="true" filter="true" filterMatchMode="startsWith" panelStyle="width: 30rem" scrollHeight="250">
<p:ajax event="itemUnselect" listener="#{bookController.onItemUnselect}"/>
<f:selectItems value="#{bookController.allAuthors}"/>
</p:selectCheckboxMenu><br/>
<p:selectOneMenu value="#{bookController.language}" >
<f:selectItems var="languages" itemValue="#{languages}" itemLabel="#{languages}" value="#{bookController.allLanguages}"/>
</p:selectOneMenu>
<p:commandButton action="#{bookController.addBook}" value="Submit" onclick="PF('dlg').hide();"/>
</p:dialog>
In the above mentioned code, I ran into an issue, where I can't use this dialog to add an Object if I try to use <f:selectItems> inside of a <p:selectOneMenu> or <p:selectOneListbox>.
It works like a charm without the code snippet or even just without the <f:selectItems> like below, but when I add it back and click on the button, the dialog will close without the action being done (#{bookController.addBook})
<p:selectOneMenu value="#{bookController.language}" >
</p:selectOneMenu>
How could I fix this issue or is there a workaround for this kind of problem?
UI: All the lists are populates and there are no constraints/field requirements, which could affect the action.
Update:
Okay, I managed to set up a converter for it, however it seems like a converter/<p:selectOneMenu> issue to me.
Converter
package aria.web.librarian;
import aria.domain.dao.LanguageDao;
import aria.domain.ejb.Language;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
import javax.inject.Inject;
import java.util.List;
#FacesConverter(value = "selectLanguageConverter")
public class SelectLanguageConverter implements Converter {
#Inject
private LanguageDao languageDao;
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
if (modelValue == null) {
return ""; // Never return null here!
}
if (modelValue instanceof Language) {
return String.valueOf(((Language) modelValue).getLanguageId());
} else {
throw new ConverterException(new FacesMessage(modelValue + " is not a valid Warehouse"));
}
}
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
List<Language> allLanguages = languageDao.getLanguages();
Language language = languageDao.getForLanguageId(Long.parseLong(submittedValue));
return language;
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(submittedValue + " is not a valid Languagae ID"), e);
}
}
}
SelectOneMenu
<p:selectOneMenu value="#{bookController.language}" converter="selectLanguageConverter">
<f:selectItem itemLabel="Choose one" itemValue="#{null}"/>
<f:selectItems value="#{bookController.allLanguages}" var="language"
itemLabel="#{language.languageName}" itemValue="#{language}"/>
</p:selectOneMenu>
The problem still occurs with converter as well, but for some reason, when putting a breakpoint to the method of Submit button, it will not stop, so I can't check the values there.
However, when putting a breakpoint to the getAsObject method of my SelectLanguageConverter, I can see, that it's get called and get's the actual Language (which is selected), but the window just closes and the button does not call BookController.addBook.
What could cause this issue and how could this be solved?
Thank you in advance.
Primefaces 8.0.RC3
Maven v4.0.0

Addig custom converter(s) (tried several types), however the only working solution I found is to use SelectItemsConverter of omnifaces.
<h:selectOneMenu value="#{bean.selectedItem}" converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{bean.availableItems}" />
</h:selectOneMenu>
with the following dependency
<dependency>
<groupId>org.omnifaces</groupId>
<artifactId>omnifaces</artifactId>
<version>3.11.1</version>
</dependency>
and html tags in my *.xhtml
xmlns:o="http://omnifaces.org/ui"
xmlns:of="http://omnifaces.org/functions"
After replacing my custom converters, the <p:selectOneMenu> worked as intended.

Related

How to execute managed bean method on selectOneMenu change?

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.

Using converter for custom objects in selectCheckboxMenu doesn't work [duplicate]

This question already has an answer here:
<f:selectItems> only shows toString() of the model as item label
(1 answer)
Closed 6 years ago.
I am trying to use an converter for custom objects, that are used in a primefaces' selectCheckboxMenu.
This is the JSF part:
<p:outputLabel value="#{msg.cars}: " for="cars" />
<p:selectCheckboxMenu id="cars"
value="#{controller.selected.cars}"
converter="carConverter" label="#{msg.cars}"
filter="true" filterMatchMode="startsWith"
panelStyle="width:200px">
<f:selectItems
value="#{controller.available.cars}" />
<f:converter converterId="carConverter" />
</p:selectCheckboxMenu>
And this is my converter:
#FacesConverter("carConverter")
public class CarConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String newValue) {
return null;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object object) {
if (object == null) {
return "";
}
if (object instanceof Car) {
Car car = (Car) object;
String name = car.getName();
return name;
} else {
throw new ConverterException(new FacesMessage(object + " is not a valid car"));
}
}
}
getAsString() returns the correct String. But the selectCheckboxMenu still lists the objects and not the Strings.
Am I missing something?
If you need to show the car name in checkboxMenu label you have to use the selectItems' itemLabel attribute
<p:outputLabel value="#{msg.cars}: " for="cars" />
<p:selectCheckboxMenu id="cars"
value="#{controller.selected.cars}"
converter="carConverter"
filter="true" filterMatchMode="startsWith"
panelStyle="width:200px">
<f:selectItems value="#{controller.available.cars}" var="car" itemLabel="#{car.name}" itemValue="#{car}"/>
</p:selectCheckboxMenu>
BTW don't declare two converters (one via converter attribute and the other via f:converter), and override correctly the getAsObject method (it's needed during the Apply Request Values phase). Check the docs for the details

How to skip validation phase in p:ajax

I bumped into that problem today at work. To make long story short I want to skip validation phase (in fact also not check required attribute) while using p:ajax component, though I want to update model in bean.
To illustrate the problem:
View:
<h:form>
<p:messages id="msg" />
<p:selectBooleanCheckbox value="#{bean.flag}">
<p:ajax listener="#{bean.flagChanged}" update="#form" />
</p:selectBooleanCheckbox>
<p:inputText value="#{bean.value}" required="true"
disabled="#{bean.flag}" validator="#{bean.validate}">
<p:ajax event="keyup" update="msg" />
</p:inputText>
<p:commandButton />
</h:form>
Bean:
public class Bean {
private Integer value;
private Integer prevValue;
private boolean flag;
public void flagChanged() {
if (!flag) {
value = prevValue;
} else {
prevValue = value;
value = null;
}
}
// value and flag setters and getters
public void validate(FacesContext facesContext, UIComponent uiComponent, Object value) {
Integer number = (Integer) value;
if (number == 7) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "7 is my lucky number", ""));
}
}
}
Checkbox is to disable and enable input text simultaneously hiding value when it is disabled and restoring it when it is enabled. Problem occures when user fills wrong value that is validated immediately and therefore not updated into the bean. So after clicking and unclicking checkbox previous correct value is restored. The very same situation happens while deleting previous value and leaving blank field (required is set to true and hence again previous value is restored).
I tried to set immediate=true, but that changes nothing, so I'm wondering if there is any way to skip validation phase in p:ajax. Maybe I am trying to achieve this in not exactly proper way (any hints appreciated!), but I would like to know if that approach is somehow possible to accomplish.
I thought there is built-in solution that solves that problem. As no one seems to exist I present my workaround to this problem (although it's not really answer to my question, becouse validation is still processed, I just ignore validation in my own validator).
<h:form>
<p:messages id="msg" />
<p:selectBooleanCheckbox value="#{bean.flag}">
<p:ajax listener="#{bean.flagChanged}" update="#form" />
</p:selectBooleanCheckbox>
<p:inputText value="#{bean.value}"
required="#{not empty param[submitButton.clientId]}" disabled="#{bean.flag}"
validator="#{bean.validate}">
<p:ajax event="keyup" update="msg" />
</p:inputText>
<p:commandButton action="#{bean.submit}" update="#form" binding="#{submitButton}">
<f:param name="validate" value="true" />
</p:commandButton>
</h:form>
Validation method:
public void validate(FacesContext facesContext, UIComponent uiComponent, Object value) {
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
if (!params.containsKey("validate")) {
return;
}
Integer number = (Integer) value;
if (number == 7) {
throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "7 is my lucky number", ""));
}
}
One way I can think of is to use <p:commandButton> with ajax="false" to submit the form. In addition, in your validator method, add the following line to check for ajax submission of the value:
if (FacesContext.getCurrentInstance().isPostback()) return;
In this case, using immediate="true" in <p:ajax> does not help because the <p:inputText> component will still be converted and validated as usual. The only difference is that it would go through this process earlier than other components on the page. Hope this helps :)

primefaces selectitem onclick event [duplicate]

This question already has answers here:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
(12 answers)
Closed 3 years ago.
I need some help. I'm developing for jsf and primefaces web application and I'm facing a problem when I'm selecting from a drop down list to get the selected value but I'm getting an empty string in the action.
This is my xhtml code for selectOneMenu tag
<p:selectOneMenu value="#{tanAllot.batchName}" id="batchName">
<f:selectItem itemLabel="Select Batch" itemValue="" />
<f:selectItems value="#{tanAllot.batchList}" />
<p:ajax event="change" listener="#{tanAllot.test}" />
</p:selectOneMenu>
this is the method I'm using in the action class
private String batchName;
public String getBatchName() {
return batchName;
}
public void setBatchName(String batchName) {
this.batchName = batchName;
}
public void test() {
System.out.println(batchName);
}
My problem is when I select a value from p:selectOneMenu tag the default method should invoke in the action and retrieve the value but I'm getting an empty string.
Can anyone help me to solve this problem?
Consider the nature of batchList. batchList must be List of Strings. Using itemValue attribute (in f:selectItem) can be helpful.
Check my example. It uses a list of provinces (instances of "Province" class). However I only need the "id" value which is a "Long"; if I wanted the whole picked province as a "Province object" I would need a "Converter". (Example works perfectly):
<p:selectOneMenu id="provinceField"
value="#{addAddressesMB.formAddress.provinceId}">
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems value="#{addAddressesMB.provinceList}" var="i"
itemLabel="#{i.description}" itemValue="#{i.id}" />
<p:ajax update=":formId:cityField"
listener="#{addAddressesMB.provinceChangeHandler}" />
</p:selectOneMenu>
And here comes the listener method:
public void provinceChangeHandler() {
//do whatever you want with formAddress.provinceId
System.out.println(this.formAddress.provinceId);
//In my case I filter the cities according to the selected provinceId
// After that I update the cities dropdown(cityField) in the view.
}
Check your code and feel free to ask. Good luck.

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