Mekswoll
Mekswoll

Reputation: 1433

commandLink action not performed

I have the following XHTML:

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
    <head>
        <title>TODO supply a title</title>
    </head>
    <body>
        <f:metadata>
            <f:viewParam id="productCV" name="productName" value="#{productBean.product}"
                         converter="#{productConverter}" required="true"/>
        </f:metadata>

        <ui:composition template="/templates/mastertemplate.xhtml">
            <!-- Define the page title for this page-->
            <ui:define name="pageTitle">
                <h:outputFormat value="#{msgs.productPageTitle}">
                    <f:param value="#{productBean.product.description}"/>
                </h:outputFormat>
            </ui:define>

            <!-- Pass the categoryName parameter to the sidebar so the category of this product is highlighted-->
            <ui:param name="categoryName" value="#{productBean.product.categoryName}"/>

            <ui:define name="content">
                <!-- If productconversion failed, show this error-->
                <h:message id="error" for="productCV" style="color: #0081c2;" rendered="#{productBean.product == null}" />

                <!-- If productconversion succeeded show the product page-->
                <h:panelGroup rendered="#{productBean.product != null}">
                    <p>#{productBean.product.description} #{productBean.product.categoryName}</p>
                    <h:form>
                        <h:commandLink action="#{cartBean.addItemToCart(productBean.product)}">
                            <f:ajax event="action" render=":cart :cartPrice" />
                            <h:graphicImage value="resources/img/addToCart.gif"/>
                        </h:commandLink>
                    </h:form>
                </h:panelGroup>
            </ui:define>
        </ui:composition>
    </body>
</html>

At the top I accept a String as GET param which I run through a converter and then get a Product object, I place this in the productBean.product, that bean has a setter and getter for the Product attribute, that's all.

I then use this object to show info etc. this works fine. I also add commandLink to add it to my cart using AJAX. This refuses to work if my ProductBean is in RequestScope, when I put it in SessionScope it works, but will only add the product 1 time.

As best I know this should be a straight forward RequestScope, I don't understand why it does work with SessionScope.

I have read through this post but I don't think I'm violating any of those rules.

For completeness, this is my ProductBean:

import be.kdg.shop.model.stock.Product;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;

@Named
@RequestScoped
public class ProductBean {

    private static final Logger logger = Logger.getLogger(ProductBean.class.getName());
    private Product product;

    public ProductBean() {}

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }
}

Upvotes: 3

Views: 13297

Answers (1)

BalusC
BalusC

Reputation: 1109635

Your bean is request scoped. So the bean instance lives as long as a single HTTP request-response cycle.

When the page with the form is requested for the first time, a new bean instance is created which receives a concrete product property as view parameter. After generating and sending the associated response, the bean instance is garbaged, because it's the end of the request.

When the form is submitted, effectively a new HTTP request is fired and thus a new bean instance is created with all properties set to default, including the product property. This way #{productBean.product} is null for the entire request. The rendered attribute of a parent component of the command link will evaluate false. The command link action is therefore never decoded. This matches point 5 of commandButton/commandLink/ajax action/listener method not invoked or input value not updated which you already found, but apparently didn't really understood.

The solution is to put the bean in the view scope. A view scoped bean lives as long as you're interacting (submitting/postbacking) with the same JSF view. Standard JSF offers @ViewScoped for this. As you're using CDI instead of JSF to manage beans, your best bet is the CDI @ConversationScoped. This is relatively clumsy (you've to start and end the scope yourself), so some CDI extension such as MyFaces CODI which offers a @ViewAccessScoped may be more useful.

See also:

Upvotes: 9

Related Questions