1

I'm having trouble making a dataTable where each row has a inputText and a commandLink. When the link is clicked, only it's row's inputText's data is submitted.

Something like this?

<h:dataTable value="#{bean.items}" var="item">
    <h:column>
        <h:inputText value="#{bean.value}"/>
    </h:column>
    <h:column>
        <h:commandLink action="#{bean.save}" value="save">
            <f:setPropertyActionListener target="#{bean.item}" value="#{item}" />
        </h:commandLink>
    </h:column>
</h:dataTable>

Bean:

@RequestScoped
public class Bean {

    private Item item;
    private String value;

Right now, as it is, it's using the last row's inputText to fill the value. I wrapped another h:form, but it broke other things and I've learned that nested h:form is not the right way to do it hehe

What's the correct way to do this?

Thanks.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
eric17859
  • 418
  • 1
  • 5
  • 17

1 Answers1

6

You're binding the value of all HTML input elements to one and same bean property. This is of course not going to work if all those HTML input elements are inside the same form. All values are subsequently set on the very same property in the order as the inputs appeared in the form. That's why you end up with the last value. You'd like to move that form to inside the <h:column> (move; thus don't add/nest another one).

The usual approach, however, would be to just bind the input field to the iterated object.

<h:inputText value="#{item.value}"/>

An alternative, if you really need to have your form around the table, is to have a Map<K, V> as bean property where K represents the type of the unique identifier of the object behind #{item} and V represents the type of value. Let's assume that it's Long and String:

private Map<Long, String> transferredValues = new HashMap<Long, String>();

// +getter (no setter necessary)

with

<h:inputText ... value="#{bean.values[item.id]}" />

This way you can get it in the action method as follows:

String value = values.get(item.getId());

By the way, if you happen to target Servlet 3.0 containers which supports EL 2.2 (Tomcat 7, Glassfish 3, etc), then you can also just pass the #{req} as a method argument without the need for a <f:setPropertyActionListener>.

<h:commandLink ... action="#{bean.save(item)}" />

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks! I was just reading your dataTable tut I can't bind to the iterated object, because it doesn't have it and I'm not supposed to modify it. But moving the form worked! What should I do if I need to use another column's inputText? – eric17859 Mar 17 '12 at 04:31
  • I updated the answer with an alternative. It requires some more boilerplate, but as you're apparently not allowed to change the object behind `#{req}`, this is the best what you can get. – BalusC Mar 17 '12 at 04:35
  • Thanks! thought something like that, but didn't think it's that simple :) – eric17859 Mar 17 '12 at 04:45