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());
}
}
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.
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());
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With