tags:

views:

1258

answers:

2

I have a databale on index.xhtml

<h:dataTable style="border: solid 2px black;"
    value="#{IndexBean.bookList}" var="item"
    binding="#{IndexBean.datatableBooks}">

    <h:column>
        <h:commandButton value="Edit" actionListener="#{IndexBean.editBook}">
            <f:param name="index" value="#{IndexBean.datatableBooks.rowIndex}"/>
        </h:commandButton>
    </h:column>
</h:dataTable>

My bean:

@ManagedBean(name="IndexBean")
@ViewScoped
public class IndexBean implements Serializable {
    private HtmlDataTable datatableBooks;

    public HtmlDataTable getDatatableBooks() {
        return datatableBooks;
    }

    public void setDatatableBooks(HtmlDataTable datatableBooks) {
        this.datatableBooks = datatableBooks;
    }

    public void editBook() throws IOException{
        int index = Integer.parseInt(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("index").toString());
        System.out.println(index);
    }
}

My problem is that I always get the same index in server log even though I click the different edit buttons. Imagine that there is one collection which is supplied to the datatable. I have not shown that in bean.

If I change scope from ViewScope to RequestScope it works fine. What can be the problem with @ViewScoped? Thanks in advance :)

EDIT:

<h:column>
    <h:commandButton value="Edit" actionListener="#{IndexBean.editBook}" />
</h:column>

public void editBook(ActionEvent ev) throws IOException{
    if (ev.getSource() != null && ev.getSource() instanceof HtmlDataTable) {
        HtmlDataTable objHtmlDataTable = (HtmlDataTable) ev.getSource();
        System.out.println(objHtmlDataTable.getRowIndex());
    }
}
A: 

What you can do is to use the [getRowData()][1] method on the Java bean to directly get the object located on the line that hosts the button on which the user clicked.

An example of code:

public void editBook(ActionEvent evt) {
    // We get the table object
    HtmlDataTable table = getParentDatatable((UIComponent) evt.getSource());
    // We get the object on the selected line.
    Object o = table.getRowData();
    // Eventually, if you need the index of the line, simply do:
    int index = table.getRowIndex();
    // ...
}

// Method to get the HtmlDataTable.
private HtmlDataTable getParentDatatable(UIComponent compo) {
    if (compo == null) {
        return null;
    }
    if (compo instanceof HtmlDataTable) {
        return (HtmlDataTable) compo;
    }
    return getParentDataTable(compo.getParent());
}


Edit

The JSF code now looks like:

<h:commandButton value="Edit" actionListener="#{IndexBean.editBook}"/>

In addition, do not forget to change the signature of editBook() method, by setting a javax.faces.event.ActionEvent argument.

romaintaz
Hello romaintaz, but i tried your solution and it doesn't seem to work. I keep getting exceptions "SEVERE: Received 'javax.el.MethodNotFoundException' when invoking action listener '#{IndexBean.editBook}' for component 'j_idt35'SEVERE: javax.el.MethodNotFoundException: Method not found: [email protected]()"Please help :(
Ankit Rathod
See my edit, it may solves your problem.
romaintaz
Hello, Please read my edit. I did exactly what you said and i still get exception MethodNotFoundException. I did not understand what you meant by "In addition, do not modify to change the signature of editBook() method, by setting a javax.faces.event.ActionEvent argument."I don't have anything defined in faces-config.xml. As soon as i pass ActionEvent it starts saying MethodNotFoundException
Ankit Rathod
Sorry, I meant "do not *forget* to modify the method signature". Remove the `throws IOException` as it is useless. In addition, the code of your method is wrong in your edit, as the source will not be the `HtmlDatatable` itself. You will have to implement the `getParentDatatable()` method as specified to retrieve the datatable object.
romaintaz
Hi romaintaz, The method still doesn't work. It gives MethodNotFoundException. Have you tried it?
Ankit Rathod
+1  A: 

You've already bound the <h:dataTable> component to the bean. All you need to do is:

public void editBook() throws IOException{
    int index = datatableBooks.getRowIndex(); // Actually not interesting info.
    Book book = (Book) datatableBooks.getRowData(); // This is what you want.
}

The <f:param> is also not needed here. For more hints also see this article.

Update: I can reproduce your problem. This is likely a bug with @ViewScoped. When the bean is set to @RequestScoped, it works as expected. Also when you remove the component binding and obtain the component from the viewroot yourself, it works as expected. I've filed issue 1658 about this.

BalusC
Hi BalusC, your article is great as usual :). Your answer works if my bean is @RequestScoped. But my real question still remains that is, why is it not working in @ViewScoped? If i just change annotation from @RequestScoped to @ViewScoped, i always get the answer that i got 1st time. I need my bean to be @ViewScoped. What workaround can i possibly do?
Ankit Rathod
Where do you load `bookList`?
BalusC
I load it in @PostConstruct callback. Am i doing something wrong? Where should i load ?
Ankit Rathod