This question already has answers here:
How to get both label and value from f:selectItems
(5 answers)
Closed 7 years ago.
I need your help in getting the values of a list into two variables. My list is having descriptions and codes. However, I need to place the descriptions in a variable and the codes in a different variable, so how can I achieve this.
My Code is
private String[] selectedCertificates;
private List<SelectItem> Certificates;
public List<SelectItem> getCertificatesList(){
Certificates = new ArrayList<SelectItem>();
Certificates.add(new SelectItem("Certificate A","A"));
Certificates.add(new SelectItem("Certificate B","B"));
return bankCertificates;
}
public void setCertificates(List<SelectItem> Certificates) {
this.Certificates = Certificates;
}
// Setters and Getters
Select Item Code:
<p:selectManyCheckbox id="Certificates" value="#{user.selectedCertificates}"
layout="pageDirection" disabled="#{user.secondToggle}">
<f:selectItems value="#{user.Certificates}" var="bankCertificates"
itemLabel="#{user.CertificatesString}" itemValue="#{user.CertificatesCode}"/>
</p:selectManyCheckbox>
where can I define that the description should be the first value and the code should be the second value in the list and I can use them in the page.
Thanks
Try
class SelectItem {
private String code;
private String description;
SelectItem (String code, String description) {
this.code = code;
this.description = description;
}
public String getCode () {
return code;
}
public String getDescription () {
return description;
}
}
Here is your main class
class MainClass {
public static void main (String...arg) {
//construct your list here using SelectItem class objects
List<SelectItem> certificates = = new ArrayList<SelectItem>();
certificates.add(new SelectItem("Certificate A","A"));
certificates.add(new SelectItem("Certificate B","B"));
//now first read the SelectItem objects you have added to the list
//or you can also iterate through the list, modify accordingly
SelectItem si1 = certificates.get(0);
//to read the code and description use the getters defined in SelectItem
si1.getCode(); si1.getDescription();
}
}
You can also choose to create a method to which you can pass the index which you wish to read from the list. Hope, this helps.
Try to do as folows if you have getters on your SelectItem bean (I have supposed you have fields description and code), it stores your object fields which is at first position in your ArrayList.
String description = Certificates.get(0).getDescription();
String code = Certificates.get(0).getCode();
Related
I have a static List of Select Items in one of my backing beans:
private static List<SelectItem> countries = new ArrayList<SelectItem>();
with the following getters and setters:
public static List<SelectItem> getCountries() {
return countries;
}
public static void setCountries(List<SelectItem> countries) {
LoadSelectItemsBean.countries = countries;
}
I am having trouble with accessing the static List through my XHTML page. The code I have tried is as follows:
<ace:simpleSelectOneMenu id="countryField"
value="#{generalCarrierDataViewBean.carrierBean.countryId}">
<f:selectItems value="#{loadSelectItemsBean.countries}" />
<ace:ajax />
</ace:simpleSelectOneMenu>
The problem line is:
<f:selectItems value="#{loadSelectItemsBean.countries}" />
The exception which results is:
javax.el.PropertyNotFoundException: /pages/GeneralCarrierData.xhtml #394,64 value="#{loadSelectItemsBean.states}": Property 'states' not found on type com.oag.reference.util.LoadSelectItemsBean
Can anbody advise on how to correctly reference a static property from a backing bean?
Thanks
Properties are per definition not static. So getters and setters can simply not be static, although they can in turn reference a static variable. But the outside world does not see that.
You've 3 options:
Remove the static modifier from the getter. The whole setter is unnecessary, you can just remove it.
public List<SelectItem> getCountries() {
return countries;
}
Create an EL function if you really insist in accessing static "properties" (functions). Detail can be found in this answer: How to create a custom EL function to invoke a static method?
Turn the whole List<SelectItem> thing into an enum and make use of OmniFaces <o:importConstants>. Detail can be found in this answer: How to create and use a generic bean for enums in f:selectItems?
Just create a non-static method that returns the static property:
// here you have a static String
private static String static_str;
public static String getStatic_str() {
return static_str;
}
// in jsf page: #{myClass.str}
public String getStr() {
return static_str;
}
I am trying to add SelectItem objects to Set collection. However, duplicate values are being added. Is there any way to prevent these duplicate values?
for(String s: list) {
Set<SelectItem> typeSet = new HashSet<SelectItem>();
typeSet.add(new SelectItem(s));
}
Just use Set<String> instead of Set<SelectItem>. The SelectItem#equals()/#hashCode() isn't implemented at all to take the actual value into account.
private Set<String> typeSet;
#PostConstruct
public void init() {
List<String> list = getItSomehow();
typeSet = new LinkedHashSet<String>(list);
}
It's since JSF2 just usable on <f:selectItems> as well.
<f:selectItems value="#{bean.typeSet}" />
See also:
Our selectOneMenu wiki page
This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 6 years ago.
I am using the managedBean userHome in requestScope, in which the entity 'user' is going to be persist.
The user has the leader column which is mapped in ManyToOne relation.My Code looks like this
#ManagedBean
#RequestScoped
public class UserHome {
private User user = new User();
// Getters and Setters
private List<SelectItem> selectItems = new ArrayList<SelectItem>();
public UserHome() {
for(User user: availableLeaders) {
selectItems.add(new SelectItem(user.getName(), user));
}
}
public void persis();
}
User.java
public class User {
#Id
#Column
private Integer id;
#Column
privat String name;
#ManyToOne
private User leader;
}
I am trying to get the value of this leader through h:selectOneMenu like this
<h:selectOneMenu value="#{userHome.user.leader}" converter="userConverter">
<f:selectItems value="#{userHome.selectItems}"/>
</h:selectOneMenu>
My converter looks like this
#FacesConverter(forClass = User.class, value="userConverter")
public class UserConverter implements Converter {
private Map<String, User> userValues = new HashMap<String, User>();
public UserConverter() {
init();
}
#Override
public Object getAsObject(FacesContext context, UIComponent component,
String value) {
return userValues.get(value);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
System.out.println("RAJASEKARAN "+value);
return ((User)value).getName();
}
public void init() {
UserHome userHome = new UserHome();
for(User user:userHome.availableLeaders()) {
userValues.put(user.getName(), user);
}
}
}
While try to save the user I am getting the error UserEdit:j_idt18: Validation Error: Value is not valid
Adding to BalusC's answer: after the postback, you need to make sure that the User instances are either exactly the same ones as you used for rendering the select items, or that you implement equals for your User class.
The code doesn't show where availableLeaders comes from, but if this is fetched from a DB on-demand, then the converter will not convert to the exact same object instance that's in the list that JSF resolves via #{userHome.selectItems}.
After the conversion, JSF will check whether the converted instance can be found in that list using the equals() method.
You've constructed the SelectItem the wrong way. As per the class' documentation, the 1st argument should represent the item value (which is to be converted and submitted) and the 2nd argument should represent the item label (which is to be displayed in list). But you specified them the other way round.
Fix it accordingly:
selectItems.add(new SelectItem(user, user.getName()));
If that still doesn't fix the problem, then it means that the equals() method of User class is not (properly) implemented. JSF will use it to validate the selected User against any of the item values of the list after conversion.
Unrelated to the concrete problem, it may be useful to know that <f:selectItems> in JSF2 offers you the possibility to build the list without the need to build a list of SelectItem manually. Here's an example which achieves exactly the same:
<f:selectItems value="#{userHome.availableLeaders}" var="user"
itemValue="#{user}" itemLabel="#{user.name}" />
This allows you to get rid of the additional selectItems property and the loop in the bean constructor.
I have tried working with the grouped selections with something like this :
<h:selectOneMenu value="#{selectionLabBean.oneSelectMenuGroup}"
id="SelectOneMenuGroup" >
<f:selectItems value="#{selectionLabBean.heroGroupList}" />
</h:selectOneMenu>
<p:message for="SelectOneMenuGroup" />
where the heroGroupList is something like this :
SelectItem[] heroArr = new SelectItem[] {
new SelectItem("Paladin"),
...
};
heroListWithGrouping.add(
new SelectItemGroup("Human",
"A collection of human race Heroes",
false,
heroArr
)
);
.....
And i'm left wondering if i can do this kind of grouping with POJOs instead of SelectItem objects ?
If i couldnt achieve this, i think i have to somehow convert my domain objects or my query results into arrays of SelectItem to make it work.
Any ideas ?
That's indeed not possible when you want to use SelectItemGroup. You need to convert from collection of POJO's to List<SelectItem> in a double for-loop during bean's (post)construction.
#PostConstruct
public void init() {
List<HeroRace> heroRaces = getItSomehowFromDatabase();
this.heroGroupList = new ArrayList<SelectItem>();
for (HeroRace heroRace : heroRaces) {
SelectItemGroup group = new SelectItemGroup(heroRace.getName()); // Human, etc
List<SelectItem> heroes = new ArrayList<SelectItem>();
for (Hero hero : heroRace.getHeroes()) {
heroes.add(new SelectItem(hero.getName()); // Paladin, etc
}
group.setSelectItems(heroes.toArray(new SelectItem[heroes.size()]));
this.heroGroupList.add(group);
}
}
You could also use Hero as item value
heroes.add(new SelectItem(hero, hero.getName()); // Paladin, etc
so that you can bind #{selectionLabBean.oneSelectMenuGroup} to a Hero type instead of String. But then you need to supply a Converter. That part is already answered by Amorfis.
Yes, you can return List or array of POJOs instead of SelectItems. You'll need converter for this to work, but it's not a big deal. So, converter first:
#FacesConverter(forClass=Hero.class)
public class HeroConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
return new Hero(value);
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return ((Hero)value).getName();
}
}
Now if you return list of Heroes to <f:selectItems>, you have options in HTML where label is Hero.toString(), and value is returned from HeroConverter.getAsString().
One more thing. If you submit some value for this selection, JSF converts it to object and checks (by equals() method) if this object was in list of objects for selection. So in case above, you'll need to override equals() in Hero to check if names are equal. Another solution is not to create new instance in getAsObject, but to keep somewhere list of available Heroes and return this list to <f:selectionItems> and return object from this list in getAsObject().
I'm having a hard time with a selectManyCheckbox.
Basically what I am doing is loading a List of Categories in a selectManyCheckbox type controller (have done this either with a List or with a List with convertEntity). My problem is with the selected elements (value="#{cardListProvider.categoriesHolder.selectedCategories}"). After some reading I understand it also has to be a List, but what kind? And how can I set the selected categories? I'm not saving them in DB but I need to run some action in the bean with them!
Here's what I have:
<h:selectManyCheckbox id="supportCategoryCardFilter"
value="#{cardListProvider.categoriesHolder.selectedCategories}" styleClass="greyText" required="false" >
<s:selectItems var="filterList" value="#{cardListProvider.categoriesList}" label="#{filterList.label}" />
<a:support id="supportCategoryCardFilter2" event="onchange"
reRender="someHolder, categoriesPanel" eventsQueue="onchange" action="#{cardListProvider.findCards(cardListProvider.categoriesHolder.selectedCategories)}" />
</h:selectManyCheckbox>
I have wasted several hours with this... Can anyone help me?
Thank you
You can bind to a String[] array like so:
public class CheckSelector {
private String[] chosen;
public String[] getChosen() { return chosen; }
public void setChosen(String[] chosen) { this.chosen = chosen; }
public SelectItem[] getChoices() {
return new SelectItem[] { new SelectItem("1"), new SelectItem("2"),
new SelectItem("3") };
}
}
The value of the selectManyCheckbox should be bound to chosen. Alternatively, you can use a List:
public class CheckSelector {
private List<String> chosen;
public List<String> getChosen() { return chosen; }
public void setChosen(List<String> chosen) { this.chosen = chosen; }
public List<SelectItem> getChoices() {
return Arrays.asList(new SelectItem("1"), new SelectItem("2"),
new SelectItem("3"));
}
}
The exact rules for value support are listed in the javadoc:
If the component has an attached Converter, use it.
If not, look for a ValueExpression for value (if any). The ValueExpression must point to something that is:
An array of primitives (such as int[]). Look up the registered by-class Converter for this primitive type.
An array of objects (such as Integer[] or String[]). Look up the registered by-class Converter for the underlying element type.
A java.util.List. Assume that the element type is java.lang.String, so no conversion is required.
If for any reason a Converter cannot be found, assume the type to be a String array.
I see you are using Seam so no need to use Strings or any primitive type, you can bind directly to List. You just have to add another tag inside your selectManyCheckbox component which is and it will automatically do everything.
Better than doing all by yourself, check Seam documentation
http://docs.jboss.org/seam/2.2.0.GA/reference/en-US/html/controls.html#d0e28378