I've the following code in my edit user screen
<h:selectManyCheckbox id="selectedGroups" value="#{usersController.selectedGroups}">
<f:selectItems value="#{usersController.groupsList}" var="item" itemLabel="#{item.groupname}" itemValue="#{item.groupid}" />
</h:selectManyCheckbox>
I've user groups list with all the groups in it, and I've selectedGroups list with the groups that are enabled for the user. But, on the edit screen, they are not showing selected by default. What am I missing? Is this not the right way to bind selected many checkboxes?
An item value of the groupsList will be preselected only when equals() method has returned true for at least one item in the selectedGroups.
Assuming that groupid is a Long, then the selectedGroups should return a List<Long> containing the values to be preselected.
Following code will work perfectly for request scope bean...
xhml code....
<h:selectManyCheckbox binding="#{Page1.chk_1}">
<f:selectItem binding="#{Page1.chk_1_options}"/>
</h:selectManyCheckbox>
Java code....
HtmlSelectManyCheckbox chk_1 = new HtmlSelectManyCheckbox();
UISelectItems chk_1_options = new UISelectItems();
public HtmlSelectManyCheckbox getChk_1() {
return chk_1;
}
public void setChk_1(HtmlSelectManyCheckbox chk_1) {
this.chk_1 = chk_1;
}
public UISelectItems getChk_1_options() {
if (chk_1_options.getValue() == null) {
List<SelectItem> lst_chk_options = new ArrayList<SelectItem>();
lst_chk_options.add(new SelectItem(1, "Label1"));
lst_chk_options.add(new SelectItem(2, "Label2"));
chk_1_options.setValue(lst_chk_options);
}
return chk_1_options;
}
public void setChk_1_options(UISelectItems chk_1_options) {
this.chk_1_options = chk_1_options;
}
If you want for session scope then reply, because binding elements in session scope giving problems in some cases...
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 am developing a JSF application
I have 2 selectOnemenu controls and submit button.
I need to disable the button if the values of 2 fields are equal
<h:selectOneMenu id="from" value="#{currencyBean.history.fromCurrency}" >
<f:selectItems value="#{currencyBean.currency}" var="c" itemValue="#{c}" itemLabel="#{c.name}"/>
</h:selectOneMenu>
<p:outputLabel for="to" value="to:" />
<h:selectOneMenu id="to" value="#{currencyBean.history.toCurrency}" >
<f:selectItems value="#{currencyBean.currency}" var="c" itemValue="#{c}" itemLabel="#{c.name}"/>
</h:selectOneMenu>
<p:commandButton id="calculateButton" value="Convert" update=":convert :historyPanel" onstart="PF('statusDialog').show()" onsuccess="PF('statusDialog').hide()" validateClient="true" ajax="true" action="#{currencyBean.Calculate()}" />
I tried to use onchange with ajax but everytime I change one dropdown the value of the second drowpdown became null in the backbean so I cannot read it.
Here is my backbean
#Named(value = "currencyBean")
#RequestScoped
public class CurrencyBean implements Serializable {
/**
* Creates a new instance of CurrencyBean
*/
private History history;
private Currency currency;
private Date currentDate;
#Inject
private Loginbean loginBean;
private List<History> historyList;
public List<History> getHistoryList() {
int userId = loginBean.getUserId();
if (userId != -1) {
return new HistoryHelper().GetHistoryListByUser(userId);
}
return null;
}
public CurrencyBean() {
history = new History();
}
public History getHistory() {
return history;
}
public void setHistory(History history) {
this.history = history;
}
public Currency[] getCurrency() {
return Currency.values();
}
public Date getCurrentDate() {
return new Date();
}
public void Calculate() {
int userId = loginBean.getUserId();
if (userId != -1) {
new CurrencyClient().Convert(userId, this.history);
}
}
}
any clue ?
My assumption is that all of your problems come from your managed bean scope. You have #Request scope so every request your managed bean will be removed from container, thus when you define onchange="submit()" (this is only my assumption because you haven't define how you implement onchange attribute) and you select value from one selectBox component values for this component is updated but the first one is still null. When you select second selectBox value updated from first selectBox doesn't exists anymore as managed bean has been removed after first request. You should try with wider scope for instance #ViewScope. If it doesn't help then further informations like implementation onchange attribute will be needed
There are three tables in MySQL database, category, sub_category and brand (manufacturer) where category is a parent of the rest i.e. sub_category and brand. I hope, the relationship between menus can be clearer based on the table relationships.
All of three <p:selectOneMenu>s are placed inside a <p:dataTable> in three respective columns as identified by <p:column>. I am ignoring <p:column>, <p:cellEditor>, <f:facet name="output">, <f:facet name="input">, <p:rowEditor> and all such nuisances for brevity.
row corresponds to a JPA managed entity which is product in this case as specified by var="row" in the <p:dataTable> associated.
This is the actual question mark : When an item (the first one) with a null value in the categoryList (parent) is selected, its child lists subCategoryList and brandList should be rest to empty.
Category List:
<p:selectOneMenu id="categoryList"
value="#{row.category}"
required="#{param['javax.faces.source'] ne component.clientId}">
<f:selectItem itemLabel="Select"
itemValue="#{null}"/>
<!-- When this item is selected, its children below should be reset to empty. -->
<f:selectItems var="category"
value="#{productManagedBean.categories}"
itemLabel="Select"
itemValue="#{category}"/>
<p:ajax update="subCategoryList brandList"/>
<!-- The listener functionality is left incomplete here. -->
</p:selectOneMenu>
Subcategory List :
<p:selectOneMenu id="subCategoryList"
value="#{row.subCategory}">
<f:selectItem itemLabel="Select"
itemValue="#{null}"/>
<f:selectItems var="subCategory"
value="#{productManagedBean.getSubCategories(row.category)}"
itemLabel="#{subCategory.subCatName}"
itemValue="#{subCategory}"
rendered="true"/>
</p:selectOneMenu>
Brand (manufacturer) List :
<p:selectOneMenu id="brandList"
value="#{row.brand}">
<f:selectItem itemLabel="Select"
itemValue="#{null}"/>
<f:selectItems var="brand"
value="#{productManagedBean.getBrands(row.category)}"
itemLabel="#{brand.brandName}"
itemValue="#{brand}"
rendered="true"/>
</p:selectOneMenu>
The managed bean (lazy data model can be ignored in the context of this question) :
#Named
#ViewScoped
public class ProductManagedBean extends LazyDataModel<Product> implements Serializable {
#Inject
private Service service;
// Associated with <p:selectOneMenu id="categoryList">.
private List<Category> categories; // Getter & setter.
// These are merely helper maps to reduce possible database calls.
private Map<Category, List<SubCategory>> subCategoriesByCategory;
private Map<Category, List<Brand>> brandByCategory;
public ProductManagedBean() {}
#PostConstruct
private void init() {
// This can be application scoped somewhere else as per business requirement.
categories = service.getCatgeoryList();
subCategoriesByCategory = new HashMap<Category, List<SubCategory>>();
brandByCategory = new HashMap<Category, List<Brand>>();
}
// This method populates <f:selectItems> associated with <p:selectOneMenu id="brandList">.
public List<SubCategory> getSubCategories(Category category) {
// category is never null here unless something is broken deliberately.
if (category == null) {
return null;
}
List<SubCategory> subCategories = subCategoriesByCategory.get(category);
if (subCategories == null) {
subCategories = service.findSubCategoriesByCategoryId(category.getCatId());
subCategoriesByCategory.put(category, subCategories);
}
return subCategories;
}
// This method populates <f:selectItems> associated with <p:selectOneMenu id="brandList">.
public List<Brand> getBrands(Category category) {
// category is never null here unless something is broken deliberately.
if (category == null) {
return null;
}
List<Brand> brands = brandByCategory.get(category);
if (brands == null) {
brands = service.findBrandsByCategoryId(category.getCatId());
brandByCategory.put(category, brands);
}
return brands;
}
}
In any case, the selected value in any of these menus is not supplied to the corresponding backing bean. It is only available in the model backed by JPA (value="#{row.category}", value="#{row.subCategory}" and value="#{row.brand}" respectively).
► How to signal the backing bean that the first item with a nullvalue (labelled "Select") in the parent menu is selected so as to resetting its child lists to empty? This should happen in any feasible way, if this is not feasible.
I am using PrimeFaces 5.2 final (community release) and Mojarra 2.2.12.
This is not needed unless there is a null foreign key in the underlying database table specifically using the vendor specific ON DELETE SET NULL option allowing an optional parent in each (or some) corresponding child row.
To the point, you need to make sure that the <f:selectItem> getter is called with a null argument. In other words, the #{row.category} must be null. Given that you're for #{row.category} using the model als shown in this answer, Populate p:selectOneMenu based on another p:selectOneMenu in each row of a p:dataTable, most likely as below,
#Transient
private Category category;
public Category getCategory() {
return (category == null && subCategory != null) ? subCategory.getCategory() : category;
}
then the #{row.category} will actually never be null when there's a subCategory. This will be the case when an existing data entry is presented in view.
You basically need to explicitly null out the subCategory (and brand) when the transient category property is explicitly set to null. This oversight has in the meanwhile been fixed in the mentioned answer. Here's how your new setCategory() method should look like:
public void setCategory(Category category) {
this.category = category;
if (category == null) {
subCategory = null;
brand = null;
}
}
This way, the getCategory() will properly return null and thus the passed-in #{row.category} also.
I want to create selectOneRadio list and selectCheckboxMenu which items get from related bean objects.
For non selected list it is working well.But how can i provide these lists with some item(s) selected by default.
My current selectCheckboxMenu code is like this.
<p:selectCheckboxMenu id="trdays"
value="#{mybean.selectedDay}"
label="Select Days">
<f:selectItems value="#{mybean.dayList}" var="day"
itemValue="#{day.value}" itemLabel="#{day.name}"/>
</p:selectCheckboxMenu>
it should look like this when page loaded and user haven't done anything yet.
EDIT
Day Class :-
public class Day{
private String name;
private String value;
//getters and setters
}
Value attribute of selectCheckboxMenu component should get the your default values.
On bean side you should write a getter for selectedDayList and all daylist.
Example:
#PostConstruct
public void init() {
dayList= new ArrayList<String>();
dayList.add("Mon");
dayList.add("Tue");
dayList.add("Wed");
dayList.add("Thu");
dayList.add("Fri");
dayList.add("Sat");
dayList.add("Sun");
selectedDayList= new ArrayList<String>();
selectedDayList.add("Tue");
selectedDayList.add("Wed");
}
public List<String> getDayList()
{
return dayList;
}
public List<String> getSelectedDaylist()
{
return selectedDayList;
}
.xhtml page should be like this.
<p:selectCheckboxMenu id="trdays"
value="#{mybean.selectedDaylist}"
label="Select Days">
<f:selectItems value="#{mybean.dayList}" var="day"
itemValue="#{day.value}" itemLabel="#{day.name}"/>
</p:selectCheckboxMenu>
Good Luck!
Just add default values in the selectedDay list (or array) in init method (with #PostConstruct annotation). These values should have same value as corresponding itemValue attribute (in your case this is day.value).
I have a problem with selecting rows in the Primefaces Datatable. I use dynamic columns, so the standard row selection mechanism is not usable here, I implement checkbox selection myself.
To help, here's s simplified version of what I have in my xhtml:
<h:form>
<p:dataTable id="table"
var="result"
value="#{tableBean.results}">
<p:columns value="#{tableBean.columnNames}" var="column" columnIndexVar="colIndex">
<f:facet name="header">
#{column}
</f:facet>
<h:panelGroup rendered="#{colIndex==0}">
<h:outputLabel>#{rowIndex}</h:outputLabel>
<h:selectBooleanCheckbox value="#{tableBean.selectedRows[result[0]]}"/>
</h:panelGroup>
</p:columns>
</p:dataTable>
<h:commandButton value="Submit"></h:commandButton>
</h:form>
And here's what I have in the managed bean to select the checkboxes:
package testpackage;
import java.util.*;
import javax.faces.bean.*;
#ManagedBean
#SessionScoped
public class TableBean
{
private Map<String, Boolean> selectedRows = new HashMap<String, Boolean>();
List<List<String>> results = new LinkedList<List<String>>();
public TableBean()
{
List<String> row1 = new LinkedList<String>();
List<String> row2 = new LinkedList<String>();
row1.add("row1.ref");
row1.add("row1.id");
row1.add("row1.status");
row2.add("row2.ref");
row2.add("row2.id");
row2.add("row2.status");
results.add(row1);
results.add(row2);
//selectedRows.put("row2.ref", true);
}
public Map<String, Boolean> getSelectedRows()
{
return selectedRows;
}
public String submit()
{
List<List<String>> selectedResults = new ArrayList<List<String>>();
for (List<String> result : results)
{
if (selectedRows.get(result.get(0)) != null)
{
selectedResults.add(result);
selectedRows.remove(result.get(0));
}
}
return null;
}
public List<List<String>> getResults()
{
return results;
}
public List<String> getColumnNames()
{
List<String> columnNames = new LinkedList<String>();
columnNames.add("");
columnNames.add("REF");
columnNames.add("ID");
columnNames.add("STATUS");
return columnNames;
}
}
The getSelectedRows method works great, but the problem is that the setSelectedRows method is never called, so I don't know which checkboxes the user has selected. Maybe I overlook something very trivial, but cannot find the solution.
Any ideas on this? I would be very glad if you helped, or give any other row selection solution for the dynamic columns.
Thx in advance,
Levi
To me it looks you are rendering the wrong field in selectBooleanCheckBox.
You should be using variable or field from the result variable.
My solution:
In your situation you are rendering an object from List as a form of table row so if you want to make some changes and retrieve the status of that row then you should be using the variable from that object only.
I understand you are submitting the whole form and want to pickup all updated rows, in that case you will have to loop through the whole List and find all the rows which have been updated by checking the status in Request Handler(Action) bean.
Hope that helps.
The setter is never called for nested objects. You're the one who's responsible for creating them, not JSF. JSF just gets the nested object and then calls the setter on it (which is the put() method in case of a Map). You just need to determine the selected rows in the action method. Add an action method to the commandbutton:
<h:commandButton value="Submit" action="#{bean.submit}"></h:commandButton>
which is definied like follows (guessing/assuming that var="result" is in essence an Object[]):
public String submit() {
List<Object[]> selectedResults = new ArrayList<Object[]>();
for (Object[] result : results) {
if (selectedRows.get((String) result[0])) {
selectedResults.add(result);
selectedRows.remove(result[0]); // Reset.
}
}
// Now selectedResults contains all selected results.
}