Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get selected row index in JSF datatable?

Tags:

java

jsf

facelets

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());
    }
}
like image 626
TCM Avatar asked May 06 '10 07:05

TCM


2 Answers

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.

like image 110
BalusC Avatar answered Oct 11 '22 00:10

BalusC


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.

like image 23
Romain Linsolas Avatar answered Oct 11 '22 00:10

Romain Linsolas