I want to make a selectOneMenu dropdown so I can select a status on my question. Is it possible to make the f:selectItem more flexible considering what happens if the order of the enums changes, and if the list was large? And could I do this better? And is it possible to automatically "select" the item that the question have?
Enum class
public enum Status {
SUBMITTED,
REJECTED,
APPROVED
}
Question entity
#Enumerated(EnumType.STRING)
private Status status;
JSF
<div class="field">
<h:outputLabel for="questionStatus" value="Status" />
<h:selectOneMenu id="questionStatus" value="#{bean.question.status}" >
<f:selectItem itemLabel="Submitted" itemValue="0" />
<f:selectItem itemLabel="Rejected" itemValue="1" />
<f:selectItem itemLabel="Approved" itemValue="2" />
</h:selectOneMenu>
<hr />
</div>
JSF has a builtin converter for enum, so this should do:
#Named
#ApplicationScoped
public class Data {
public Status[] getStatuses() {
return Status.values();
}
}
with
<h:selectOneMenu value="#{bean.question.status}" >
<f:selectItems value="#{data.statuses}" />
</h:selectOneMenu>
(note: since JSF 2.0 there's no need anymore to provide a SelectItem[] or List<SelectItem>, a T[] and List<T> are accepted as well and you can access the current item by var attribute)
If you happen to use JSF utility library OmniFaces, then you could use <o:importConstants> instead of a bean.
<o:importConstants type="com.example.Status" />
<h:selectOneMenu value="#{bean.question.status}" >
<f:selectItems value="#{Status}" />
</h:selectOneMenu>
If you intend to control the labels as well, you could add them to the Status enum:
public enum Status {
SUBMITTED("Submitted"),
REJECTED("Rejected"),
APPROVED("Approved");
private String label;
private Status(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}
with
<f:selectItems value="#{data.statuses}" var="status"
itemValue="#{status}" itemLabel="#{status.label}" />
Or, better, make the enum value a property key of a localized resource bundle (EL 3.0 required):
<f:selectItems value="#{data.statuses}" var="status"
itemValue="#{status}" itemLabel="#{text['data.status.' += status]}" />
with this in a properties file associated with resource bundle #{text}
data.status.SUBMITTED = Submitted
data.status.REJECTED = Rejected
data.status.APPROVED = Approved
For localization we can use also this solution:
public enum Status { SUBMITTED, REJECTED, APPROVED }
data.status.SUBMITTED=Submitted
data.status.REJECTED=Rejected
data.status.APPROVED=Approved
<h:selectOneMenu value="#{bean.question.status}" >
<f:selectItems
value="#{data.statuses}"
var="status"
itemValue="#{status}"
itemLabel="#{text['data.status.'.concat(status)]}" />
</h:selectOneMenu>
So the resource path for localization strings are not hardcoded in Enum.
You could use <f:selectItems value="#{carBean.carList}" /> and return a list of SelectItem instances that wrap the enum (use Status.values() to get all possible values).
You can use following utility el function to obtain the enum values and use them in a SelectOneMenu for example. No need to create beans and boilerplate methods.
public final class ElEnumUtils
{
private ElEnumUtils() { }
/**
* Cached Enumerations, key equals full class name of an enum
*/
private final static Map<String, Enum<?>[]> ENTITY_ENUMS = new HashMap<>();;
/**
* Retrieves all Enumerations of the given Enumeration defined by the
* given class name.
*
* #param enumClassName Class name of the given Enum.
*
* #return
*
* #throws ClassNotFoundException
*/
#SuppressWarnings("unchecked")
public static Enum<?>[] getEnumValues(final String enumClassName) throws ClassNotFoundException
{
// check if already cached - use classname as key for performance reason
if (ElEnumUtils.ENTITY_ENUMS.containsKey(enumClassName))
return ElEnumUtils.ENTITY_ENUMS.get(enumClassName);
final Class<Enum<?>> enumClass = (Class<Enum<?>>) Class.forName(enumClassName);
final Enum<?>[] enumConstants = enumClass.getEnumConstants();
// add to cache
ElEnumUtils.ENTITY_ENUMS.put(enumClassName, enumConstants);
return enumConstants;
}
}
Register it as an el function in a taglib file:
<function>
<description>Retrieves all Enumerations of the given Enumeration defined by the given class name.</description>
<function-name>getEnumValues</function-name>
<function-class>
package.ElEnumUtils
</function-class>
<function-signature>
java.lang.Enum[] getEnumValues(java.lang.String)
</function-signature>
</function>
And finally call it like:
<p:selectOneMenu value="#{bean.type}">
<f:selectItems value="#{el:getEnumValues('package.BeanType')}" var="varEnum"
itemLabel="#{el:getEnumLabel(varEnum)}" itemValue="#{varEnum}"/>
</p:selectOneMenu>
Similiar to BalusC answer you should be using a resource bundle with localized enum labels and for cleaner code you can also create a function like getEnumLabel(enum)
Related
I am working on a JSF page which has a dropdown based on List<SelectItem>:
<h:selectOneMenu value="#{bean.selectedItem}">
<f:selectItems value="#{bean.availableItems}" />
</h:selectOneMenu>
I need to get both the value and label of the currently selected item. Right now I only get the value. How can I get the label, too?
You can't. That's just how HTML works. You know, JSF is a HTML code generator. The JSF <h:selectOneMenu> generates a HTML <select><option> . The HTML <select> element will only send the value attribute of the selected <option> element. It will not send its label.
But that shouldn't be a big issue. You namely already know both the value and label in the server side, inside the #{bean.availableItems}. All you need to do to get the associated label is to get it by the value as key. I suggest to make it a Map which in turn can also be used in f:selectItems.
Basic kickoff example:
public class Bean {
private String selectedItem; // +getter +setter
private Map<String, String> availableItems; // +getter
public Bean() {
availableItems = new LinkedHashMap<String, String>();
availableItems.put("value1", "label1");
availableItems.put("value2", "label2");
availableItems.put("value3", "label3");
}
public void submit() {
String selectedLabel = availableItems.get(selectedItem);
// ...
}
}
with
<h:selectOneMenu value="#{bean.selectedItem}">
<f:selectItems value="#{bean.availableItems.entrySet()}" var="entry"
itemValue="#{entry.key}" itemLabel="#{entry.value}" />
</h:selectOneMenu>
and in result
<p>Selected label is #{bean.availableItems[bean.selectedItem]}</p>
An alternative is to wrap both name and value in a javabean object representing an entity and set the whole object as value, via a converter.
See also:
Our selectOneMenu wiki page
How to populate options of h:selectOneMenu from database?
Instead of Using Map I tried like this and it's perfectly working for me to get both ItemValue and ItemLabel in the same property by using "ItemValue" attribute in selectItems tag.How ever provided no extra commas in the ItemLabel(#asfas....i had the same problem u mentioned so i selected this approach).
<h:selectOneMenu value="#{company.issueDesc}" required="true" onchange="submit()">
<f:selectItem itemLabel="-- Select a Issue -- " itemValue="0"/>
<f:selectItems value="#{company.issueList}" var="model" itemLabel="#{model.IssueDesc}" itemValue="#{model.Code},#{model.IssueDesc}" >
</f:selectItems>
</h:selectOneMenu>
Basically IssueDesc is String type in Bean Company
public Class Company{
private String issueDesc; // getters and setters
private int code; // getters and setters
private List<T>issueList; // getters and setters.
public void getLblandVal(){
String desc=getIssueDesc();
String[] str_ary=desc.split(",");
String s1=str_ary[0];
String s2=str_ary[1];
// parse **s1** to int;
}
}
What if the the value should be Integer and label String and both are needed in backing bean. Using Map in bean doesn't work because JSF interprets the map key as label. Ideally it would be a LinkedHashMap and search the text by a number.
Seems upside down to search number (value) by a text (key). What if some implementation of JSF adds extra space to test or letter case changes for some reason. Then the value is not found from map.
This will do the trick.
private String getLabel(List<SelectItem> list, String selection) {
String label = "";
for (int i = 0; i < list.size(); i++) {
if(selection.equals((String)list.get(i).getValue())) {
label = (String)list.get(i).getLabel();
break;
}
}
return label;
}
In your example, you would pass in the availableItems as 'list' and selectedItem as 'selection'. This method will return the label value corresponding to the selectedItem.
The following approach may also be useful in getting value and label using List <SelectItem>:
Here, facade, statesFacade fetches list of states from database/enterprise bean.
In view (xhtml page):
<h:selectOneMenu id="statesSelectUi" value="#{applicationBean1.state}">
<f:selectItems value="#{applicationBean1.stateSelectItems}"/>
<f:ajax render="selectedItem" event="change" execute="statesSelectUi"/>
</h:selectOneMenu>
<br/>
<br/>
<h:outputText id="selectedItem" value="#{applicationBean1.selectedState}"/>
In the Managed Bean(applicationBean1.java):
private String state;
/**
* #return the stateSelectItems
*/
public List<SelectItem> getStateSelectItemsItems() {
stateSelectItems.add(new SelectItem("-1","--- Select state ---"));
int statesCount = statesFacade.count();
List<StateSelectItems> states;
states = statesFacade.findAll();
for (int i = 0; i < statesCount; i++) {
stateSelectItems.add(new SelectItem(states.get(i).getStateSlNo(), states.get(i).getStateName()));
}
return stateSelectItems;
}
public String getSelectedState(){
if("".equals(getState()) || getState() ==null){
return "";
}else{
return "Selected State : " + getStateSelectItems.get(Integer.parseInt(getState())).getValue()+", "++ getStateSelectItems.get(Integer.parseInt(getState())).getLabel();
}
}
I followed the advice from How to use enum values in f:selectItem(s) to build a h:selectOneMenu that takes the values of an enum. This works fine until I reload the page.
If I reload the page (Strg+R) what a user could do, the #{bean.relationship} property becomes null. All other properties, such as strings, numbers, etc. remain as they were before (Bean is #ViewScoped and #ManagedBean).
Here is the code from the JSF:
<h:selectOneMenu value="#{bean.relationship}">
<f:selectItems value="#{bean.relationshipTypes}"
var="types" itemValue="#{types}" itemLabel="#{types}" />
</h:selectOneMenu>
<h:inputText value="#{bean.name}" />
Here the code from the Enum:
public enum RelationshipType {
Family,
Friend
}
Here the code from the Bean:
private RelationshipType relationship; // plus getter & setter
private RelationshipType[] relationshipTypes;
private String name; // plus getter & setter
public RelationshipType[] getRelationshipTypes() {
return RelationshipType.values();
}
The enum is part of a larger entity. For ease of display a shortend version. Any idea?
#Geinmachi: Yet, other values stored in the bean are still there after the reload (e.g. name). So, why not for the property related to the enum?
I have used enums for data types
Enum
public enum Datatypes {
INT("Int"), FLOAT("Float"), DOUBLE("Double"), STRING("String"), DATE("Date"), DATETIME(
"DateTime"), BLOB("Blob");
private final String dataType;
private Datatypes(String dataType) {
this.dataType = dataType;
}
public String getDataType() {
return this.dataType;
}
#Override
public String toString() {
return dataType;
}
}
Bean
private List<Datatypes> datatypes = Arrays.asList(Datatypes.values());
public List<Datatypes> getDatatypes() {
return datatypes;
}
public void setDatatypes(List<Datatypes> datatypes) {
this.datatypes = datatypes;
}
xhtml
<p:selectOneMenu value="#{bean.dataType}">
<f:selectItem itemLabel="Select Data type"/>
<f:selectItems value="#{bean.dataTypes}" />
</p:selectOneMenu>
it working for me.
This question already has answers here:
How to populate options of h:selectOneMenu from database?
(5 answers)
Closed 6 years ago.
I want to pick a custom object from select one menu. It neither shows an error nor values. What should I do?
My xhtml document:
<h:panelGrid columns="2">
<p:outputLabel value="" />
<p:selectOneMenu id="CurrencyMenu" value="#{CurrencyMB.currency}" >
<f:selectItem itemLabel="-- Select Currency--" itemValue="#{null}"/>
<f:selectItems value="#{CurrencyMB.currencyList}" var="currency" itemValue="#{currency.currencyId}" itemLabel="#{currency.currencyName}" >
</f:selectItems>
<p:ajax update="currencyOut" />
</p:selectOneMenu>
<p:outputLabel value="Currency Id : #{CurrencyMB.currency.currencyId}" id="currencyOut" />
</h:panelGrid>
My managedBean class:
#ManagedBean(name = "CurrencyMB")
#RequestScoped
public class CurrencyManagedBean {
private Currency currency;
private List<Currency> currencyList;
public Currency getCurrency() {
return currency;
}
public void setCurrency(Currency currency) {
this.currency = currency;
}
public List<Currency> getCurrencyList() {
currencyList = new ArrayList<Currency>();
currencyList.addAll(getiCurrencyService().getCurrencies());
return currencyList;
}
public void setCurrencyList(List<Currency> currencyList) {
this.currencyList = currencyList;
}
}
You are trying to map a Java object of class Currency to a string that comes as a HTTP request parameter. A converter is intended to be used in a situation when you need to create an object from a its string representation, and vice versa, like in the situation you faced.
Basically there are two approaches.
1. Utilize converter.
With this approach you define item value as a Currency object and use a converter to create string representation from an object and recreate an object back from a string. For the converter part, just follow the tutorial Luiggi pointed at. Basically you need to create a class that implements Converter, annotate it with #FacesConverter("currencyConverter") to be able to refer to the converter by id, like in converter="currencyConverter" attribute of a JSF tag:
<p:selectOneMenu id="CurrencyMenu" value="#{CurrencyMB.currency}" converter="currencyConverter">
<f:selectItems value="#{CurrencyMB.currencyList}" var="currency" itemValue="#{currency}" itemLabel="#{currency.currencyName}" />
<p:ajax update="currencyOut" />
</p:selectOneMenu>
2. Utilize plain Strings (or java primitive wrappers).
With this approach you bind item values, as well as user selection to a bean property of String type, and not to an actual object. Using it this way you won't need any converter, and string values will be set for you:
<p:selectOneMenu id="CurrencyMenu" value="#{CurrencyMB.currencyName}">
<f:selectItems value="#{CurrencyMB.currencyList}" var="currency" itemValue="#{currency.currencyName}" itemLabel="#{currency.currencyName}" />
<p:ajax update="currencyOut" />
</p:selectOneMenu>
Finally, it is worth reading the question to the answer Why selectOneMenu Send ItemLabel to the converter?.
You can create Converter for your Custom Object Currency.
Step 1: Create a Converter class and Implement javax.faces.convert.Converter Interface,Override getAsObject and getAsString methods and write your logic for String to Object Conversion and Object to String Conversion.
Step 2: Simply declare something like #FacesConverter("currencyConverter") in your converter class or If you want use Spring Inject or Autowired Annotation in Converter class declare your Converter Class with #Component("currencyConverter") Annotation and don't use #FacesConverter.And your converter class should in component scan package.
Step 3: Declare your converter in Selectonemenu Using converter property.
If you still have any problem please refer this link
http://www.techpages.org/jsf/jsf-custom-object-converter-from-selectonemenu/2428/
I'm developing a pure JavaEE6 application with JSF 2.0 and Glassfish.
My JSF implementation is Primefaces (beside Mojarra provided by Glassfish).
I want to verify if the values of 2 password fields in a JSF form are equal.
With Seam, there is the neat component <s:validateEquality for="pw1"/>.
I want do to the same without Seam, just using JSF (or maybe a component of a JSF library). Until now i only saw examples which validate the form with a custom validator. But i would like to compare the fields without writing Java code or Javascript code.
Is that possible?
This what it looks like with Seam:
...
<h:inputSecret id="passwort" value="#{personHome.instance.password}"
redisplay="true" required="true">
<f:validateLength minimum="8"/>
<a:support event="onblur" reRender="passwortField" bypassUpdates="true" ajaxSingle="true" />
</h:inputSecret>
...
<h:inputSecret id="passwort2" required="true" redisplay="true">
<!-- find the JSF2.0-equivalent to this tag: -->
<s:validateEquality for="passwort"/>
<a:support event="onblur" reRender="passwort2Field" bypassUpdates="true" ajaxSingle="true" />
</h:inputSecret>
...
You may use Primefaces tag in this very simple way:
<p:password id="password" value="#{bean.password}" match="repeated_password" />
<p:password id="repeated_password" value="#{bean.password}" />
The Seam3 Faces module will support "Cross-field form validation" in it's imminent Alpha3 release. This is your best bet for a minimal code solution, see this blog for a howto.
Alternatively I've done this programmatically by using the f:attribute tag to pass the clientId of another form field to a custom validator, then using the UIComponent passed into the custom validator to access the other filed by id.
Here's the facelet file:
<h:outputLabel value="Enter your email address" rendered="#{!cc.attrs.registration.subRegistration}" />
<h:inputText label="Email" id="textEmail1" value="#{cc.attrs.registration.email}" rendered="#{!cc.attrs.registration.subRegistration}" required="true" maxlength="128" size="35"></h:inputText>
<h:message for="textEmail1" rendered="#{!cc.attrs.registration.subRegistration}"></h:message>
<h:outputLabel value="Re-enter your email address confirmation:" rendered="#{!cc.attrs.registration.subRegistration and cc.attrs.duplicateEmailRequired}" />
<h:inputText label="Email repeat" id="textEmail2" rendered="#{!cc.attrs.registration.subRegistration and cc.attrs.duplicateEmailRequired}" maxlength="64" size="35">
<f:validator validatorId="duplicateFieldValidator" />
<f:attribute name="field1Id" value="#{component.parent.parent.clientId}:textEmail1" />
</h:inputText>
<h:message for="textEmail2" rendered="#{!cc.attrs.registration.subRegistration and cc.attrs.duplicateEmailRequired}"></h:message>
Here's the validator class:
package ca.triumf.mis.trevents.jsf.validator;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
#FacesValidator(value="duplicateFieldValidator")
public class DuplicateFieldValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value)
throws ValidatorException {
// Obtain the client ID of the first field from f:attribute.
System.out.println(component.getFamily());
String field1Id = (String) component.getAttributes().get("field1Id");
// Find the actual JSF component for the client ID.
UIInput textInput = (UIInput) context.getViewRoot().findComponent(field1Id);
if (textInput == null)
throw new IllegalArgumentException(String.format("Unable to find component with id %s",field1Id));
// Get its value, the entered text of the first field.
String field1 = (String) textInput.getValue();
// Cast the value of the entered text of the second field back to String.
String confirm = (String) value;
// Check if the first text is actually entered and compare it with second text.
if (field1 != null && field1.length() != 0 && !field1.equals(confirm)) {
throw new ValidatorException(new FacesMessage("E-mail addresses are not equal."));
}
}
}
I had to use a mixture of both answers to succeed.
I used ifischers short solution but my bean password field was null.
So I used the lines from Brian Leathem to get the UIInput from the context:
public void passwordValidator(FacesContext context, UIComponent toValidate, Object value) {
UIInput passwordField = (UIInput) context.getViewRoot().findComponent("registerForm:password");
if (passwordField == null)
throw new IllegalArgumentException(String.format("Unable to find component."));
String password = (String) passwordField.getValue();
String confirmPassword = (String) value;
if (!confirmPassword.equals(password)) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Passwords do not match!", "Passwords do not match!");
throw new ValidatorException(message);
}
}
If you're using JSF utility library OmniFaces, then you could use <o:validateEqual>. It also allows setting a custom message. The showcase has a live example demonstrating the common usecase of validating the password confirmation. You don't even need ajax to update the model before invoking the validator (as your own approach does).
Here's the minimum necessary code:
<h:inputSecret id="password" value="#{personHome.person.password}" />
<h:message for="password" />
<h:inputSecret id="password2" />
<h:message for="password2" />
<o:validateEqual components="password password2"
message="Passwords do not match!" showMessageFor="password2" />
No Java code needed.
This is the way i finally did it, which i like cause it's short and easy. The only problem is that it's not really re-usable, but as i only need this in one case, i rather save some LOCs and do it this way.
Snippet from my view:
<h:inputSecret id="password" value="#{personHome.person.password}">
<f:ajax event="blur" render="passwordError" />
</h:inputSecret>
<h:message for="password" errorClass="invalid" id="passwordError" />
<h:inputSecret id="password2" validator="#{personHome.validateSamePassword}">
<f:ajax event="blur" render="password2Error" />
</h:inputSecret>
<h:message for="password2" errorClass="invalid" id="password2Error" />
My Backing Bean (just the important part):
#Named #ConversationScoped
public class PersonHome {
private Person person;
public Person getPerson() {
if (person == null) return new Person();
else return person;
}
public void validateSamePassword(context:FacesContext, toValidate:UIComponent, value:Object) {
String confirmPassword = (String)value;
if (!confirmPassword.equals(person.getPassword()) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Passwords do not match!", "Passwords do not match!")
throw new Validatorexception(message);
}
}
You can do it easily with Apache MyFaces ExtVal.
Without solution, I was forced to do the validation in a ugly way (not recommended). At least it works till I found better solution.
In the method that returns the action, I check both values, in case of different values, I add error messages on context and return null to the navigation handler.
package com.jsf.beans.user;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.component.html.HtmlInputSecret;
import org.apache.commons.lang.StringUtils;
import com.pichler.jsf.beans.base.JsfViewBean;
#ManagedBean(name = "changePassword")
#RequestScoped
public class ChangePassword extends JsfViewBean {
private HtmlInputSecret inputSecret1, inputSecret2;
/**
* #return the inputSecret1
*/
public HtmlInputSecret getInputSecret1() {
return inputSecret1;
}
/**
* #param inputSecret1
* the inputSecret1 to set
*/
public void setInputSecret1(HtmlInputSecret inputSecret1) {
this.inputSecret1 = inputSecret1;
}
/**
* #return the inputSecret2
*/
public HtmlInputSecret getInputSecret2() {
return inputSecret2;
}
/**
* #param inputSecret2
* the inputSecret2 to set
*/
public void setInputSecret2(HtmlInputSecret inputSecret2) {
this.inputSecret2 = inputSecret2;
}
private String password1, password2;
public String alterar() {
if (!StringUtils.equals(password1, password2)) {
addErrorMessage(inputSecret1.getClientId(),
"As senhas não coincidem");
addErrorMessage(inputSecret2.getClientId(),
"As senhas não coincidem");
return null;
}
return null;
}
/**
* #return the password1
*/
public String getPassword1() {
return password1;
}
/**
* #param password1
* the password1 to set
*/
public void setPassword1(String password1) {
this.password1 = password1;
}
/**
* #return the password2
*/
public String getPassword2() {
return password2;
}
/**
* #param password2
* the password2 to set
*/
public void setPassword2(String password2) {
this.password2 = password2;
}
}
*JsfViewBean is just a class that has some common methods, as "addMessages".
I have a <h:selectOneMenu> that has <f:selectItems> with CategoryHistory objects loaded in it. I only show the Date date field as itemLabel.
That works but I want to format the date:
I created a converter that extends javax.faces.convert.DateTimeConverter and change the fields in the constructor. But my dates only show in default format :(
DateAndTimeConverter.java
import javax.faces.bean.ManagedBean;
import javax.faces.convert.Converter;
import javax.faces.convert.DateTimeConverter;
import javax.faces.convert.FacesConverter;
#FacesConverter(value = "dateAndTimeconverter")
#ManagedBean
public class DateAndTimeConverter extends DateTimeConverter implements Converter {
public DateAndTimeConverter(){
this.setDateStyle("short");
}
xhtml
<h:selectOneMenu valueChangeListener="#{admin.categoryHistoryListener}"
onchange="submit()" value="#{admin.categoryHistory.id}" converter="#{dateAndTimeconverter}">
<f:selectItems value="#{admin.categoryHistories}" var="n"
itemValue="#{n.id}" itemLabel="#{n.date}">
</f:selectItems>
</h:selectOneMenu>
It also doesn't work when I try:
<h:selectOneMenu valueChangeListener="#{admin.categoryHistoryListener}"
onchange="submit()" value="#{admin.categoryHistory.id}">
<f:converter converterId="dateAndTimeconverter"/>
<f:selectItems value="#{admin.categoryHistories}" var="n"
itemValue="#{n.id}" itemLabel="#{n.date}">
</f:selectItems>
</h:selectOneMenu>
CategoryHistory Has a Date date, and Long id +...
Thank you
Unfortunately, the JSF converters only applies on the input value, not on the input label.
You'll need to solve this other ways. E.g. a getter which uses SimpleDateFormat to format the date. Or if your environment supports EL 2.2, simply invoke the converter method directly (you've it as managed bean already):
<f:selectItems value="#{admin.categoryHistories}" var="n" itemValue="#{n.id}"
itemLabel="#{dateAndTimeconverter.getAsString(facesContext, component, n.date)}">
If you happen to use JSF utility library OmniFaces, then you can also use its of:formatDate() function. E.g.:
<f:selectItems value="#{admin.categoryHistories}" var="n" itemValue="#{n.id}"
itemLabel="#{of:formatDate(n.date, 'd MMM yyyy')}">
You can use a converter method in your bean, as:
public class Admin{
...
public String formatDate(Date fecha, String pattern) {
return (new SimpleDateFormat(pattern)).format(fecha);
}
...
}
And, in your xhtml page inside f:selectItems:
<f:selectItems value="#{admin.categoryHistories}" var="n"
itemValue="#{n.id}" itemLabel="#{admin.formatDate(n.date,'d MMM yyyy')}">
</f:selectItems>
Example
xhtml
<h:selectOneMenu value="#{tbMonitoreoController.fechaMonitoreo}">
<f:selectItems value="#{tbMonitoreoController.fechasMonitoreo}" />
Method in tbMonitoreoController
public SelectItem[] getFechasMonitoreo(){
Collection<Date> entities = getEjbFacade().getFechasMonitoreo();
return JsfUtil.getSelectItemsFechasMonitoreo(entities, true);
}
public static SelectItem[] getSelectItemsFechasMonitoreo(Collection<Date> listDate, boolean selectOne) {
int size = selectOne ? (listDate.size() + 1) : listDate.size();
SelectItem[] items = new SelectItem[size];
int i = 0;
if (selectOne) {
items[0] = new SelectItem(null, "---");
i++;
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy");
for (Date x : listDate) {
items[i++] = new SelectItem(x, simpleDateFormat.format(x));
}
return items;
}