5

I have a JSF view that lists items in a collection in a Primefaces DataTable. The rightmost columns contain remove buttons. When a remove button is clicked, it is supposed to make an Ajax call, remove the corresponding item from the session variable Cart and update the view in-place. I would like the request and the view change to be as minimal as possible.

Here is what I have for this purpose:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui">

<h:head>
    <title>Register user</title>
</h:head>

<h:body>
    <f:view>

        <h:form id="itemsForm">

            <p:outputPanel id="items">
                <p:dataTable value="#{cart.itemList}" var="item">

                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="name" />
                        </f:facet>
                        <h:outputText value="#{item.product.description}" />
                    </p:column>

                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="quantity" />
                        </f:facet>
                        <h:outputText value="#{item.quantity}" />
                    </p:column>

                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="" />
                        </f:facet>
                        <p:commandButton icon="ui-icon-close" title="remove from cart">
                            <p:ajax listener="#{cart.removeItem}"
                                update="form:itemsForm"
                                process="@this" />
                        </p:commandButton>
                    </p:column>

                    <f:facet name="footer">  
                        Total amount: ${cart.totalAmount}
                    </f:facet>
                </p:dataTable>

            </p:outputPanel>
        </h:form>

    </f:view>
</h:body>
</html>

Accordingly, I have the following method in Cart.java

public void removeItem() {
        System.out.println("REMOVE REQUEST ARRIVED");
}

However, the removeItem method isn't even executing when I click a remove button. So my questions are:

1) What is wrong with my Ajax call? What changes should I make to my XHTML?

2) How do I handle the request in the removeItem method and return a response?

3) How do I update the footer, which displays the totalAmount?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Murat Derya Özen
  • 2,154
  • 8
  • 31
  • 44

2 Answers2

19

You can pass #{item} as a parameter of your method call in the actionListener.

Your .xhtml page should look like this:

<p:dataTable id="cartTable" value="#{cart.itemList}" var="item">
   <p:column>
      <f:facet name="header">
         <h:outputText value="" />
      </f:facet>
      <p:commandButton icon="ui-icon-close" title="remove from cart"
                       actionListener="#{cart.removeItem(item)}" update="cartTable" />
   </p:column>
</p:dataTable>

And this is the method removeItem of your ManagedBean:

@ManagedBean
@ViewScoped
public class Cart {
   private List<Item> itemList;

   public void removeItem(Item item) {
      itemList.remove(item);
   }
}
Mr.J4mes
  • 9,168
  • 9
  • 48
  • 90
  • That's not working. The `@ViewScoped` annotation is causing an exception. When I change it to `@SessionScoped`, the button does not respond. Nothing happens on click. – Murat Derya Özen Jan 07 '12 at 14:26
  • @Murat I just tried to provide an example that you can use `#{item}` as a parameter directly without having to use ``. You definitely need to switch my example to your own use case. I can not guess what you have to give you a 100% working solution. – Mr.J4mes Jan 07 '12 at 17:00
  • except that the `actionListener` attribute should have been `action`, right? – Murat Derya Özen Jan 07 '12 at 17:32
  • @Murat Not necessary. Since you are intending to make Ajax call without needing to make any navigation, you can use `actionListener` – Mr.J4mes Jan 07 '12 at 17:41
  • 2
    The `@ViewScoped` is the only right annotation for such a bean. Perhaps you just need to **read** the exception and fix it accordingly instead of ignoring it altogether? I'd bet that it was a `NotSerializableException` which is fairly self-explaining. – BalusC Jan 08 '12 at 02:39
  • To only process the delete button, add `process="@this"`. See https://stackoverflow.com/questions/25339056/understanding-primefaces-process-update-and-jsf-fajax-execute-render-attributes – Jasper de Vries Sep 10 '20 at 11:03
2

1) <p:commandButton uses ajax by default , so instead placing the p:ajax use the action or actionListener of the <p:commandButton

2) I would use the action of the button and return null

3) update="@form" should update the entire form and this will update the entire table

here an example of a working button (link) from my page , i used the f:setPropertyActionListener to "pass" some data to the delete method

<p:commandButton action="#{cart.removeItem}" icon="ui-icon-close" title="remove from cart" update="@form" process="@this" >
      <f:setPropertyActionListener
             target="#{cart.selectedItem}"
             value="#{item}" />
</p:commandButton>

in your class add this

private Item selectedItem;

public Item getSelectedItem() {
    return selectedItem;
}


public void setSelectedItem(Item selectedItem) {
    this.selectedItem = selectedItem;
}
Daniel
  • 36,833
  • 10
  • 119
  • 200
  • Thanks for the answer. So the `hoursReportBean` in your code corresponds to the `Cart` class I have? How do you get the selected items? What is the `value` parameter there? I'm just new to all this stuff. – Murat Derya Özen Jan 07 '12 at 13:41
  • I updated the (1) bulletin of my answer , yes it corresponds to Cart class, the selected item is being set using the selectedHourReportsToDeleteFromTable , which is just an attribute of "item" type in the class with getter/seter, so just before the execution of the clicked button its being set thanks to the setPropertyActionListener , and then in the delete method you can use it – Daniel Jan 07 '12 at 14:31
  • This is driving me crazy. JSF shouldn't be that hard. It's not working. The GET request is on its way but the method is not executing... – Murat Derya Özen Jan 07 '12 at 14:39
  • you welcome , what modifications you added (might be use full for other members) – Daniel Jan 07 '12 at 15:37
  • 1
    This is the code that works for me. Assigned ids to the table and the footer. ` ` – Murat Derya Özen Jan 07 '12 at 15:49