I have a combo in my page which I want to have populated with some keywords from configuration. I want to use a managed bean to accomplish it.
Let's say that I have a bean called Config, where there is a List categories field. ..
public class Configuration implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> categories;
public List<String> getCategories() {
if (categories == null)
categories = getCats();
return categories;
}
//... etc.
}
When I use this field for my combo, it works well...
<xp:comboBox>
<xp:selectItems>
<xp:this.value><![CDATA[#{config.categories}]]></xp:this.value>
</xp:selectItems>
</xp:comboBox>
But, it's only a list of labels. I need values, too. How do I populate selectItems of my combo with TWO strings - a label and a value?
EDIT:
I tried to create an object Combo with label and value fields and use a repeat inside my comboBox.
<xp:comboBox>
<xp:repeat id="repeat1" value="#{config.combo}" var="c" rows="30">
<xp:selectItem itemLabel="#{c.label}" itemValue="#{c.value}" />
</xp:repeat>
</xp:comboBox>
Still not working... :-(
Instead of returning a List<String> your function should return a List<javax.faces.model.SelectItem>. Here's a sample:
public static List<SelectItem> getComboboxOptions() {
List<SelectItem> options = new ArrayList<SelectItem>();
SelectItem option = new SelectItem();
option.setLabel("Here's a label");
option.setValue("Here's a value");
options.add(option);
return options;
}
Advantage of using this method (besides not having to use that nonconceptual stuff :-) is that you can also the SelectItemGroup class to group the options:
public static List<SelectItem> getGroupedComboboxOptions() {
List<SelectItem> groupedOptions = new ArrayList<SelectItem>();
SelectItemGroup group = new SelectItemGroup("A group of options");
SelectItem[] options = new SelectItem[2];
options[0] = new SelectItem("here's a value", "here's a label");
options[1] = new SelectItem("here's a value", "here's a label");
group.setSelectItems(options);
groupedOptions.add(group);
return groupedOptions;
}
You can use SelectItems. (see http://docs.oracle.com/javaee/6/api/javax/faces/model/SelectItem.html)
You can specify both value and label, or value only.
import javax.faces.model.SelectItem;
public List<SelectItem> getCategories() {
try {
ArrayList<SelectItem> ret = new ArrayList<SelectItem>();
ret.add(new SelectItem("my value", "my label"));
return ret;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
Related
Hi I have a 'mail in' application and display the emails waiting in the queue (line) on a 'wallboard'. I wish to refresh the display every x seconds using a partial refresh of the repeat containing the mail data. This works fine other than the I have a problem with a date field, which displays correctly until the first refresh, when it converts to the default 1 Jan 1970. I use the created date to calculate the no. of minutes the mail has been waiting - not shown here.
Any help would be appreciated.
Many thanks
On the XPage I have:
<xp:scriptBlock
id="scriptBlockRefresh">
<xp:this.value>
<![CDATA[
setInterval(function() {
XSP.partialRefreshGet("#{id:mailInPanel}", {})
}, 5 * 1000)
]]>
</xp:this.value>
</xp:scriptBlock>
<xp:this.beforePageLoad><![CDATA[#{javascript:miniWallboardBean.loadOutstandingMailin();}]]></xp:this.beforePageLoad>
<xp:panel id="mailInPanel">
<xp:repeat id="repeat1" rows="30" value="#{miniWallboardBean.outstandingMailin}" var="rowData">
<xp:text escape="true" id="computedField1" value="#{rowData.from}"></xp:text>
<xp:text escape="true" id="computedField2" value="#{rowData.subject}"></xp:text>
<xp:text escape="true" id="computedField5" value="#{javascript:rowData.getCreatedDate().toJavaDate()}"></xp:text>
</xp:repeat>
</xp:panel>
In my Mailin Class
import lotus.domino.DateTime;
public class Mailin {
private String from;
private String subject;
private DateTime createdDate;
private String owner;
public String getFrom() {return from;}
public void setFrom(String from) {this.from = from;}
public String getSubject() {return subject;}
public void setSubject(String subject) {this.subject = subject;}
public DateTime getCreatedDate() {return createdDate;}
public void setCreatedDate(DateTime createdDate) {this.createdDate = createdDate;}
public String getOwner() {return owner;}
public void setOwner(String owner) {this.owner = owner;}
}
I get the data from view columns in my business logic:
public List <Mailin> getOutstandingMailin(){
ArrayList<Mailin> outstandingMailin = new ArrayList<Mailin>();
try {
ViewEntryCollection entries = NCLWallboardUtil.getAllEntries("Server","DB","View"); //Method to get a collection
if (entries !=null) {
ViewEntry entry = entries.getFirstEntry();
while (entry !=null){
Mailin mailin = loadMailInFromEntry(entry);
outstandingMailin.add(mailin);
ViewEntry oldEntry = entry;
entry = entries.getNextEntry(entry);
oldEntry.recycle();
}
entries.recycle();
}
} catch (NotesException e) {
e.printStackTrace();
}
return outstandingMailin;
}
private Mailin loadMailInFromEntry(ViewEntry entry) throws NotesException{
Mailin mailin = new Mailin();
mailin.setFrom((String) entry.getColumnValues().get(0));
mailin.setSubject((String) entry.getColumnValues().get(3));
mailin.setOwner((String) entry.getColumnValues().get(5));
mailin.setCreatedDate((DateTime) entry.getColumnValues().get(4));
return mailin;
}
In my session scope bean I have:
public class MiniWallboardBean implements Serializable{
private static final long serialVersionUID = 1L;
private List <Mailin> outstandingMailin;
private MiniWallboard miniWB;
public MiniWallboardBean(){
miniWB = new MiniWallboard();}
public void loadOutstandingMailin(){
try{
setOutstandingMailin(miniWB.getOutstandingMailin());
}catch (Exception e){
e.printStackTrace();
}
}
public void setOutstandingMailin(List <Mailin> outstandingMailil{
this.outstandingMailin = outstandingMailin;}
public List <Mailin> getOutstandingMailin() {
return outstandingMailin;}
DateTimes, like other Domino objects, are not serializable. So once the initially page load is completed and the Session recycled, your DateTime will also be recycled.
Store the values as Java Dates instead and you will be fine.
I have following field in my jsp. Selected value is not set to the element.
When I did Inspect element on this drop down field in FF, it shows that element is not selected. Also its not set to the backing bean.
What am I missing?
<h:selectOnMenu id="scriptEngine" value="#{AddScriptBean.scriptEngine}" required="true">
<f:selectItems value="#{AddScriptBean.scriptEngines}"/>
</h:selectOneMenu>
The backing bean code is as follows
public List<SelectItem> getScriptEngines() {
List<SelectItem> items = new ArrayList<SelectItem>();
try {
GetScriptEngineNamesCommand command = (GetScriptEngineNamesCommand) CommandFactory.getInstance().getCommand(GetScriptEngineNamesCommand.class.getName());
command.doExecute();
Map<String, String> engineNames = command.getEngineNames();
MessageSource messageSource = getMessageSource();
Locale locale = RequestUtils.getUserLocale((HttpServletRequest) FacesContext.getCurrentInstance()
.getExternalContext().getRequest(), Globals.LOCALE_KEY);
String label = messageSource.getFormattedMessage(locale, "com.soa.console.faces.script.select", new Object[] {});
items.add(new SelectItem("", label));
for (String name : engineNames.keySet()){
items.add(new SelectItem(engineNames.get(name), name));
}
}catch (GException e){
String eMessage = e.toString();
FacesMessage msg = new FacesMessage("", eMessage);
msg.setSeverity(FacesMessage.SEVERITY_ERROR);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
return items;
}
I guess getter method is not calling becuase you have bounded <f:selectItems> tag to the bean with scriptEngines but your getter method is getScriptEngines().It should have been getscriptEngines().This could be the problem
I would like to know how I can fill a h:selectManyListbox from a database, i.e. not with static options.
Use <f:selectItems> in combination with a property which returns List<SelectItem>, or when you're already on JSF 2.0, a List<SomeObject>.
<h:selectManyListbox value="#{bean.selectedItems}">
<f:selectItems value="#{bean.selectItems}" />
</h:selectManyListbox>
You can load the items from the DB in bean's constructor or #PostConstruct method.
public class Bean {
private List<String> selectedItems;
private List<SelectItem> selectItems;
public Bean() {
selectItems = new ArrayList<SelectItem>();
// Fill select items during Bean initialization/construction.
// Below is just an example, you could replace this by getting a list
// of some objects from DB and creating new items in a loop.
selectItems.add(new SelectItem("value1", "label1"));
selectItems.add(new SelectItem("value2", "label2"));
selectItems.add(new SelectItem("value3", "label3"));
}
// Getters, etc
}
In a Screen to be rendered by a JSF Implementation, I had to show a static drop down or list box (which means the values are not changing ), So I decided to use a list of select Items and in the getter of the List , I am populating all the select Items as this
List.add(new SelectItem(VALUE,TEXT)) and so on..
If I used this way - What are the pitfalls? I made this List static since this will be common for all the Request Scoped Beans the JSF Implementation creates. Is this okay to do?
Sometimes , the items are added twice if multiple requests are fired.Is there an Application Scope ? or Whats the standard way of doing these stuff?
I'm also looking into API.Sometimes SO is quicker.
I'm using JSF Apace My Faces 1.2 without Tomahawk or any extra libs
Thanks,
Sometimes , the items are added twice if multiple requests are fired.
This indicates that you're adding the items in the getter method like follows
public class Bean {
private List<SelectItem> items = new ArrayList<SelectItem>();
public List<SelectItem> getItems() {
items.add(new SelectItem("value1", "label1"));
items.add(new SelectItem("value2", "label2"));
items.add(new SelectItem("value3", "label3"));
return items;
}
}
This is not good. A javabean getter should have the sole purpose to return a bean property or at highest do lazy loading, not to do some business stuff. You should create and fill the list during bean construction
public class Bean {
private List<SelectItem> items;
public Bean() {
items = new ArrayList<SelectItem>();
items.add(new SelectItem("value1", "label1"));
items.add(new SelectItem("value2", "label2"));
items.add(new SelectItem("value3", "label3"));
}
}
or initialization
public class Bean {
private List<SelectItem> items;
{
items = new ArrayList<SelectItem>();
items.add(new SelectItem("value1", "label1"));
items.add(new SelectItem("value2", "label2"));
items.add(new SelectItem("value3", "label3"));
}
}
or #PostConstruct
public class Bean {
private List<SelectItem> items;
#PostConstruct
public void init() {
items = new ArrayList<SelectItem>();
items.add(new SelectItem("value1", "label1"));
items.add(new SelectItem("value2", "label2"));
items.add(new SelectItem("value3", "label3"));
}
}
Is there an Application Scope ?
There is. Just use <managed-bean-scope>application</managed-bean-scope>.
or Whats the standard way of doing these stuff?
An application scoped bean is the way to go.
See also:
Why does JSF call getters multiple times?
In my application i need to add a row on a click of a button and this button will be in all the rows. Need help to do this?
Item Class
public class Item {
public Item()
{
}
private String value;
public Item(String value) { this.value = value; }
public void setValue(String value) { this.value = value; }
public String getValue() { return value; }
}
Manage Bean Class
public class MyMB
{
private List<Item> list;
public void addItem() { // JSF action method
list.add(new Item("Default"));
Iterator<Item> iterator = list.iterator();
while(iterator.hasNext())
{
Item item = (Item)iterator.next();
System.out.println(item.getValue());
}
System.out.println();
}
/**
* #return the list
*/
public List<Item> getList() {
if(list==null)
{
loadList();
}
return list;
}
private void loadList() {
list = new ArrayList<Item>();
list.add(new Item("Data"));
}
}
JSF code
<h:form>
<rich:dataTable value="#{myMB.list}" var="item" id="tabel">
<h:column><h:inputText value="#{item.value}" /></h:column>
<h:column><a4j:commandButton value="Add" actionListener="#{myMB.addItem}" reRender="tabel"/></h:column>
All you need to do is basically indeed just adding an empty object to the datamodel behind the value attribute of h:dataTable.
But the same empty row needs to be preserved in the subsequent request as well. If the backing bean is request scoped, then the datamodel get reloaded without the empty row. This all should work when the bean is session scoped.
Further there are several errors in your JSF code. The h:dataTable var attribute is missing and the column content needs to be inside a h:column.
<h:form>
<h:dataTable value="#{bean.list}" var="item">
<h:column><h:inputText value="#{item.value}" /></h:column>
</h:dataTable>
<h:commandButton value="Add" action="#{bean.add}"/>
</h:form>
A session or view scoped bean can look like this:
public class Bean {
private List<Item> list;
public Bean() {
list = new ArrayList<Item>();
}
public void add() {
list.add(new Item());
}
public List<Item> getList() {
return list;
}
}
The Item class should of course have a default no-arg constructor. Normally this is already implicitly available, but if you define your own constructor with arguments, then it is not available anymore. You'll need to explicitly define it, otherwise you cannot do Item item = new Item(); anymore.
public class Item {
private String value;
public Item() {
// Keep default constructor alive.
}
public Item(String value) {
this.value = value;
}
// ...
}
If you prefer to keep the bean in the request scope, then you'll need to maintain the amount of newly added items, so that the bean can preserve the same amount on load.
public class Bean {
private List<Item> list;
private HtmlInputHidden count = new HtmlInputHidden();
public Bean() {
count.setValue(0);
}
public void add() {
list.add(new Item());
}
public List<Item> getList() {
if (list == null) loadList();
return list;
}
public HtmlInputHidden getCount() {
return count;
}
public void setCount(HtmlInputHidden count) {
this.count = count;
}
private void loadList() {
list = new ArrayList<Item>();
// Preserve list with newly added items.
for (int i = 0; i < (Integer) count.getValue(); i++) {
list.add(new Item());
}
}
}
You'll only need to add the following to the <h:form> of the JSF page:
<h:inputHidden binding="#{bean.count}" converter="javax.faces.Integer" />
For more insights about using datatables in any way you may find this article useful: Using Datatables. It also contains a WAR file with lot of examples in both request and session scope.
Take this table as an example:
<h:datatable value="#{myBean.list}" ...>
...
<h:column>
<h:commandButton value="Add a row" action="#{myBean.addRow}"/>
</h:column>
</h:datatable>
The method myBean.addRow will simply add a new element in your list:
public class MyBean {
private List<SomeClass> list;
...
public List<SomeClass> getList() {
return list;
}
public void addRow() {
list.add(new SomeClass());
}
}
When you will click on the button, the method addRow will add a new element in the list. The page will refresh and display the table with a new row.
Edit:
Regarding your post edition, three things:
Point 1: Could you please attach the stacktrace of your error?
Point 2: Your method addRow return a String which is an ID used by JSF for the navigation. As this action does not involve any navigation (i.e. the user stay on the same page), simply return null or "":
public String addRow() {
list.add(new Item("new data"));
return null;
}
Point 3: I suggest that your class Item provide an empty constructor (in addition of your current constructor):
public Item() {
}