Search code examples
jsfjsf-2hyperlinkdatatablecommandlink

<h:link> vs <h:commandLink> in <h:dataTable>


When I want to see the detail page of my Book I will get my book and redirect it to my overviewpage. Now when I use the <h:link> he always gives the last item of my dataTable. When I use the <h:commandLink> everthing works fine. Now my question, why doesn't work the <h:link outcome="..."> when the 'same' code in <h:commandLink> will work?

Managed Bean

@Named(value = "bookController")
@SessionScoped
public class BookController implements Serializable {

@EJB private BookRepository dao;
private LibraryBook book = new LibraryBook();

...

public String getLibraryBook(String isbn)
{
    this.book = this.dao.getBook(isbn);
    return "bookOverview";
} 

...

}

Book.xhtml

<f:view>
        <h:form>
            <h:dataTable value="#{bookController.books}" var="item" class="table">
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Isbn"/>
                    </f:facet>
                    <h:link value="#{item.isbn}" outcome="#{bookController.getLibraryBook(item.isbn)}"/>
                </h:column>
                <h:column>
                    <f:facet name="header">
                        <h:outputText value="Title"/>
                    </f:facet>
                    <h:outputText value="#{item.title}"/>
                </h:column>
                <h:column>
                    <h:commandButton value='Update' class="btn btn-warning" action="#{bookController.EditBook(item)}"></h:commandButton>
                    <h:commandButton value='Delete' class="btn btn-danger" action="#{bookController.deleteBook(item.isbn)}"></h:commandButton>
                </h:column>
            </h:dataTable>
        </h:form>
    </f:view>

Solution

  • Because the <h:link outcome> is evaluated at the moment the page is rendered, not when you click the link. The method you're referring in outcome sets the session scoped bean property to the current item and then returns a string bookOverview. So, effectively you end up with every single link having a outcome="bookOverview" before you click on it. In the meanwhile, the bean has only the last item remembered.

    The <h:commandLink action> works because it is evaluated after you click the link.

    This difference is because <h:link> is intented for idempotent (GET) requests which does not require a stateful <h:form>, and the <h:commandLink> is intented for non-idempotent (POST) requests which require a stateful <h:form>.

    See also:


    That said, the real problem you're trying to solve is answered here: Creating master-detail pages for entities, how to link them and which bean scope to choose. It shows how to properly use <h:link> and which bean scope you should actually be using.