Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object as itemValue in <f:selectItems> [duplicate]

Is it possible to have objects as itemValue in tag?

for example I have a class Foo:

public class Foo {
  private int id;
  private String name;
  private Date date;
}

And another class Bar

public class Bar {
  private Foo foos;
}

public class BarBean {
  private Set<Foo> foos;
}

Now in a Bean called BarBean I need to have a to get the Foo of the current Bar from User like this:

<h:selectOneMenu value="#{barBean.bar.foo}" required="true">
 <f:selectItems value="#{barBean.foos}"  var="foo" itemLabel="#{foo.name}" itemValue="#{foo}" />
</h:selectOneMenu>

---------------edited:

my converter:

package ir.khorasancustoms.g2g.converters;

import ir.khorasancustoms.g2g.persistance.CatalogValue;
import java.util.ResourceBundle;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

@FacesConverter("ir.khorasancustoms.CatalogValueConverter")
public class CatalogValueConverter implements Converter {

  @Override
  public Object getAsObject(FacesContext context, UIComponent component, String value) {
    SessionFactory factory = new Configuration().configure().buildSessionFactory();
    Session session = factory.openSession();

    try {
      int id = Integer.parseInt(value);
      CatalogValue catalogValue = (CatalogValue) session.load(CatalogValue .class, id);
      return catalogValue;
    } catch (Exception ex) {
      Transaction tx = session.getTransaction();
      if (tx.isActive()) {
        tx.rollback();
      }
      ResourceBundle rb = ResourceBundle.getBundle("application");
      String message = rb.getString("databaseConnectionFailed");
      FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_FATAL, message, message));
    } finally {
      session.close();
    }

    return null;
  }

  @Override
  public String getAsString(FacesContext context, UIComponent component, Object value) {
    return ((CatalogValue) value).getId() + "";
  }

}

and my facelet:

    <h:outputText value="#{lbls.paymentUnit}:"/>
    <h:selectOneMenu id="paymentUnit" label="#{lbls.paymentUnit}" value="#{price.price.ctvUnit}" required="true">
      <f:selectItems value="#{price.paymentUnits}"/>
      <f:converter converterId="ir.khorasancustoms.CatalogValueConverter"/>
    </h:selectOneMenu>
    <h:message for="paymentUnit" infoClass="info" errorClass="error" warnClass="warning" fatalClass="fatal"/>
like image 368
ehsun7b Avatar asked Jan 08 '11 18:01

ehsun7b


3 Answers

Yes it is possible.

You need to write a converter that will convert Foo to SelectItem

Check implementation and very good article here

like image 167
jmj Avatar answered Oct 20 '22 09:10

jmj


BalusC's article as referenced by Jigar gives two excellent solutions. It's via a converter that uses a DAO or via Strings which get converted back and forth in the backing bean.

One additional solution is a hybrid of those two. Via e.g. an f:param you can give the converter access to an EL value expression that points to the Map in the backing bean BalusC mentioned. Instead of the DAO, which might need to access the DB for each conversion, the Map is consulted.

This allows you to use the full Foo object within the <f:selectItems> tag and saves you the possible call to the DB after each post back. The cost is however some extra complexity in coding as you have to provide the converter, the parameter and the map.

(I do have to add btw that such a Map works best when the backing bean is in the view scope or a larger scope. It won't really save you on DB calls when it's in request scope)

like image 37
Arjan Tijms Avatar answered Oct 20 '22 07:10

Arjan Tijms


I'm on Myfaces 2.0.2 and this works

<h:selectOneMenu value="#{barBean.bar.foo}" required="true">
 <f:selectItems value="#{barBean.foos}"  var="foo" itemLabel="#{foo.name}" itemValue="#{foo}" />
</h:selectOneMenu>

or even better

<h:selectOneMenu value="#{barBean.bar.foo}" required="true">
 <f:selectItems value="#{barBean.foos}"  />
</h:selectOneMenu>

works , with itemLabel defaulted to foo.toString()- Dunno if it matters but foos is a List<Foo> not a Set

The <f:converter> isnt necessary if using

@FacesConverter(forClass = Foo.class)

before the FooConverter

like image 29
Manu de Hanoi Avatar answered Oct 20 '22 07:10

Manu de Hanoi