Using SelectManyCheckbox with list of objects

9.5k views Asked by At

Im trying to create a JSF page that lets the user select X amount of ingredients, and then saves those selected ingredients to a list.

Ingredient is an object with two values, String IngredientName and int ingredientPrice.

What I want to do is to create 1 selectItem per Ingredient in an IngredientList (dynamically sized), and then save the selected items to another list of ingredients.

I've tried doing this multiple different ways but either I get classcast exceptions or the checkboxes don't appear at all.

My Bean:

@ManagedBean
@SessionScoped
public class ManagedIngredientsBean {

@EJB
IngredientBean iBean;

private List<Ingredient> ingredientList;
private List<Ingredient> checkedOptions;
private List<SelectItem> selectList;

public ManagedIngredientsBean() {

}


public String createNew(){

    ingredientList = iBean.getAllIngredients();
    selectList = new ArrayList<SelectItem>(ingredientList.size());
    for(Ingredient i : ingredientList){
        selectList.add(new SelectItem(i.getIngredientName()));
    }

    return "createnew.xhtml";
}

public List<SelectItem> getSelectList() {
    return selectList;
}

public void setSelectList(List<SelectItem> selectList) {
    this.selectList = selectList;
}

public List<Ingredient> getCheckedOptions() {
    return checkedOptions;
}

public void setCheckedOptions(List<Ingredient> checkedOptions) {
    this.checkedOptions = checkedOptions;
}

public List<Ingredient> getIngredientList() {
    return ingredientList;
}

public void setIngredientList(List<Ingredient> ingredientList) {
    this.ingredientList = ingredientList;
}

@FacesConverter(value="userConverter")
public static class UserConverter implements Converter {
    public Object getAsObject(FacesContext facesContext,
                              UIComponent component, String value) {
        return value;
    }

    public String getAsString(FacesContext facesContext,
                              UIComponent component, Object o) {
        Ingredient i = (Ingredient) o;
        return i.getIngredientName();

    }
}
}

IngredientBean used to get the Ingredient items from the persistence database and returning them as a list:

@Stateless(name = "IngredientEJB")
public class IngredientBean {

    EntityManagerFactory entFactory;
    EntityManager em;

    public IngredientBean() {
        entFactory = Persistence.createEntityManagerFactory("NewPersistenceUnit");
        em = entFactory.createEntityManager();
    }

    public List<Ingredient> getAllIngredients(){
        TypedQuery<Ingredient> ingQuery = em.createQuery("SELECT i FROM Ingredient i", Ingredient.class);
        List<Ingredient> iList =  ingQuery.getResultList();

        return iList;

    }
}

My JSF Page:

<!DOCTYPE html
        PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">

<h:head>
    <title>Create New Order</title>
</h:head>

<h:body>
    <h:form>
        <h:selectManyCheckbox value = "#{managedIngredientsBean.checkedOptions}">
                <f:converter converterId="userConverter"/>
                <f:selectItem value = "#{managedIngredientsBean.selectList}" var = "item" itemLabel = "#{item.getIngredientName()}" itemValue = "#{item}"/>
        </h:selectManyCheckbox>
    </h:form>

</h:body>

</html>

I'm probably missing something obvious or simply misunderstanding how to use the selectManyCheckbox element but I'm completely stuck on how to fix this. Appreciate any answers on how I should be implementing this. :)

Edit: Forgot to mention, the createNew() method in the managed bean is called in the previous JSF page and redirects to this one.

1

There are 1 answers

2
Michele Mariotti On

your converter is broken.

first, it have to be a bean so must not be a static class.

second, it "should" be symmetric:

x.equals(c.getAsObject(ctx, comp, c.getAsString(ctx, component, x))); "should" be true.

@FacesConverter(value="userConverter")
public class UserConverter implements Converter 
{
    public Object getAsObject(FacesContext facesContext, UIComponent component, String value) 
    {
        return database.loadIngredientByUniqueValue(value);
    }

    public String getAsString(FacesContext facesContext,UIComponent component, Object o) 
    {
        Ingredient i = (Ingredient) o;
        return i.getSomeUniqueValue();
    }
}