2

I am using a pageblocktable that has a column of buttons next to each product that says "add to cart", I need to toggle this button to "remove" once the product has been added to the cart.

Using the help from this link: Toggle Command Button Value from Ascending to Descending

I was able to toggle a button from "Add to cart" to "Remove" however it is toggling ALL the buttons in the column and I need it to toggle each button individually as it is clicked.

Here is my code:

<apex:pageBlockTable value="{!products}" var="item" id="products">
                    <apex:column headerValue="Product" width="60%">
                        <apex:outputText value="{!item.Name}" />
                    </apex:column>
                    <apex:column headerValue="Product Code" width="25%">
                        <apex:outputText value="{!item.ProductCode}" />
                    </apex:column>
                    <apex:column headerValue="Product Category" width="15%">
                        <apex:outputText value="{!item.Family}" />
                    </apex:column>
                     <apex:column width="5%" style="text-align: center;">
                            <apex:commandButton value="Add to cart" action="{!AddToCart}" reRender="products" immediate="true" id="AddToCartBtn" rendered="{!showAdd}">
                                    <apex:param value="{!item.Id}" assignTo="{!productItemId}" name="addToCart"/>
                                </apex:commandButton>
                                <apex:commandButton value="Remove" action="{!RemoveFromCart}" reRender="products" immediate="true" id="RemoveFromCartBtn" rendered="{!showRemove}">
                                    <apex:param value="{!item.Id}" assignTo="{!productItemId}" name="removeFromCart"/>
                                </apex:commandButton>
                    </apex:column>
                </apex:pageBlockTable> 

Any help would be phenomenal - Thanks!

5

You need to customize showAdd and showRemove to use specific values. There's several ways you could do this, but the least painful way to do so right now without writing a ton of code is to make showAdd and showRemove per-item. Here's how that would look:

// In your controller
public Map<Id, Boolean> shouldShowAddButton { get; set; }

And in your page:

... First button
rendered="{!shouldShowAddButton[item.id]}">

... Second button
rendered="{!not shouldShowAddButton[item.id]}">

In your constructor, make sure you create a new Map<Id, Boolean> for shouldShowAddButton, and update your addToCart and removeFromCart functions to update this map accordingly.

A word of caution: Make sure your map contains a value for every product that may be rendered, or your page will crash. Visualforce doesn't like to reference non-existent keys.

In the future, you should probably consider a Wrapper class. It takes a bit more work, but has the advantage of being easier to manage. Here's one possible implementation:


public class Extension {
    Set<Id> cartIds = new Set<Id>();

    public class Wrapper {
        public Product2 product { get; set; }
        Extension extension;
        Wrapper(Extension e, Product2 p) {
            extension = e;
            product = p;
        }
        public void addToCart() {
            extension.cartIds.add(product.Id);
        }
        public void removeFromCart() {
            extension.cartIds.remove(product.Id);
        }
        public Boolean getShowAdd() {
            return !getShowRemove();
        }
        public Boolean getShowRemove() {
            return extension.cartIds.contains(product.Id);
        }
    }
    public Wrapper[] getProducts() {
        Wrapper[] results = new Wrapper[0];
        for(Product2 record:[...]) {
            results.add(new Wrapper(this, record));
        }
        return results;
    }
}

At this point, your products are "wrapped" inside some logic that let you control individual values, so you have to change your entire page slightly:

<apex:pageBlockTable value="{!products}" var="item" id="products">
    <apex:column headerValue="Product" width="60%">
        <apex:outputText value="{!item.product.Name}" />
    </apex:column>
    <apex:column headerValue="Product Code" width="25%">
        <apex:outputText value="{!item.product.ProductCode}" />
    </apex:column>
    <apex:column headerValue="Product Category" width="15%">
        <apex:outputText value="{!item.product.Family}" />
    </apex:column>
    <apex:column width="5%" style="text-align: center;">
        <apex:commandButton value="Add to cart" action="{!item.addToCart}" reRender="products" id="AddToCartBtn" rendered="{!item.showAdd}" />
        <apex:commandButton value="Remove" action="{!item.removeFromCart}" reRender="products" immediate="true" id="RemoveFromCartBtn" rendered="{!item.showRemove}" />
    </apex:column>
</apex:pageBlockTable> 

This removes the complexity of having to pass parameters, etc, by letting the wrapper do the heavy lifting for you. Communication between the individual wrapper item and the extension is handled by way of a memory reference (new Wrapper(this, record).

  • Thank you sir, on the server side, how would I reference that item.id that I pass from the client using {!shouldShowAddButton[item.id]} – Blindsyde Mar 8 '16 at 22:34
  • 1
    You'll find all of the selected items by iterating over the keySet of the Map and seeing if the value is true. Something like this: for(Id key:shouldShowAddButton.keySet()) { if(shouldshowAddButton.get(key)) /* record is in the cart */ else /* record is not in the cart */ }. Using the wrapper class I suggested is even easier: if the product Id is in the cart, it'll be in the Set as well. – sfdcfox Mar 8 '16 at 22:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.