tags:

views:

291

answers:

1

I've got the following jsf page:

    <h:form>
        <ui:repeat value="#{list.categories}" var="cat">
            <h:selectOneRadio id="sel1Rad" value="#{list.choose}" layout="pageDirection">
                <f:selectItems value="#{list.names}"/>
            </h:selectOneRadio> 
        </ui:repeat>
        <h:commandButton id="submit" action="#{list.submit}" value="Submit"/>
    </h:form>

And a component named list. The variable cat is injected to the component, used by the method list.getNames(). What I am trying to have happen is to have list.choose() be called for each radio group. I'm not sure if this is possible with Seam. Going by the booking example distributed with Seam, there is a distinct separate method for each selectOneRadio or selectOneMenu group.

Since I have an unknown number of categories, I can't / don't want to define a method for each possible choice.

When I submit the form, all my choices are sent in the POST, I just don't know the correct way to tell Seam how to dispatch them to my component.

Any help is appreciated!

+2  A: 

Make #{list.choose} an array, Collection or Map. A Map<String, String> wherein the key represents the category and the value represents the selected option is probably the easiest.

Here's an SSCCE which works right here (Mojarra 2.0.2 at Tomcat 6.0.24).

package com.stackoverflow.q2493671;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.faces.bean.ManagedBean;
import javax.faces.model.SelectItem;

@ManagedBean
public class Bean {

    private List<String> categories;
    private List<SelectItem> selectItems;
    private Map<String, String> selectedItems = new HashMap<String, String>();

    public Bean() {
        categories = Arrays.asList("cat1", "cat2", "cat3");
        selectItems = Arrays.asList(new SelectItem("item1"), new SelectItem("item2"), new SelectItem("item3"));
    }

    public void submit() {
        for (Entry<String, String> entry : selectedItems.entrySet()) {
            String category = entry.getKey();
            String selectedItem = entry.getValue();
            System.out.println(category + "=" + selectedItem);
        }
    }

    public List<String> getCategories() {
        return categories;
    }

    public List<SelectItem> getSelectItems() {
        return selectItems;
    }

    public Map<String, String> getSelectedItems() {
        return selectedItems;
    }

}

in combination with

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
>
    <h:head>
        <title>SO question 2493671</title>
    </h:head>
    <h:body>
        <h:form>
            <ui:repeat value="#{bean.categories}" var="category">
                <h:selectOneRadio value="#{bean.selectedItems[category]}" layout="pageDirection">
                    <f:selectItems value="#{bean.selectItems}" />
                </h:selectOneRadio>
            </ui:repeat>
            <h:commandButton value="submit" action="#{bean.submit}" />
        </h:form>
    </h:body>
</html>
BalusC
Thanks for the quick reply! I tried this, and the Entry Set is empty on submit. I do see `getSelectedItems()` being called for every radio group, but `setSelectedItems()` is never called, nor is the map populated...
purecharger
It was theory, but it ought to work. So I just tried to create an SSCCE and it just works here. I've updated the question with copy'n'paste'n'runnable code. See if it works for you. If you are on JSF 1.x yet, just replace `@ManagedBean` by the obvious `<managed-bean>` declaration in `faces-config.xml`. Your problem is probably that you didn't prepopulate the `categories` as it was in the initial request.
BalusC
By the way, JSF indeed won't call the bean setter for collections and maps. It instead first gets the collection/map and then uses its item setter (the `add()` method for collections and the `put()` method for maps).
BalusC
I tried your example exactly, and it does work in my environment, alongside my own Seam component. However, I cannot get mine to work. I am able to display each radio group, select the buttons, see the values transported in the POST, but the `Map<String, String> selectedItems` is not populated. I've verified in both the debugger and via logging that `getSelectedItems()` is called for each radio group, and is returning the same object every time.
purecharger
How about `categories`? It sounds like that it doesn't return the same list in the subsequent request.
BalusC
Ah, now I understand your earlier comment, and yes I believe you are correct. I was instantiating a new `List` on every call to `getCategories()`. So now I am storing the categories in a `Map<String, List<String>`, with the key being a URL parameter. It works correctly for the first request to the page, from another page where the param is set, but subsequent requests do not have the parameter. Back to figuring out the correct `<page/>` definitions...Thanks for your help!
purecharger
Try `a4j:keepAlive`.
BalusC