0

I have a visualforce page that contains the following snippet:

    <apex:pageBlockTable id="qliList" value="{!qliProdList}" var="qliProd" columns="3">
        <apex:column >
            <apex:facet name="header">Name</apex:facet>
            {!qliProd.Name}
        </apex:column>
        <apex:column >
            <apex:facet name="header">Quantity</apex:facet>
            <apex:outputText value="{!qliQuantity}">
                <apex:param name="qliID" value="{!qliProd.Id}"/>
            </apex:outputText>
        </apex:column>
        <apex:column >
            <apex:facet name="header">Action</apex:facet>
            <apex:commandButton action="{!delQLI}" rerender="qliList" value="Remove">
                <apex:param name="qliID" value="{!qliProd.Id}"/>
            </apex:commandButton>
        </apex:column>
    </apex:pageBlockTable>

I have the following relevant apex code:

public class MyController {
    public List<QuoteLineItem> qliList = new List<QuoteLineItem>();
    public MyController() {

        // some code that instantiates (but does not insert) quote line items 
        // and adds them to qliList. Code is omitted for brevity

    }

    public List<Product2> get QliProdList() {
        List<Product2> qliProdList = new List<Product2>();
        for (QuoteLineItem qli : qliList) {
            Product2 prod = [SELECT Id, Name FROM Product2 WHERE Id = :qli.Product2Id]; 
            qliProdList.add(prod);
        }
        return qliProdList;
    }

    public Double getQLIQuantity() {
        String qliID = ApexPages.CurrentPage().getParameters().get('qliID');
        system.debug('trying to get QLI quantity for ID: ' + qliID);
        for (QuoteLineItem qli : qliList) {
            if (qli.Product2Id == qliId) {
                return qli.Quantity;
            }
        }
        return null;
    }

    public void delQLI() {
        String qliID = ApexPages.CurrentPage().getParameters().get('qliID');
        for (Integer i = qliList.size() - 1; i >= 0; i--) {
            if (qliList[i].Product2Id == qliID) {
                qliList.remove(i);
            }
        }
        return;
    }
}

The "remove" commandButton works beautifully. However, I can't get the quote line item's quantity value in the apex:outPutText. qliID comes back null. I did some googling and apparently people are saying that I need to make a wrapper class for my qliProdList. However, I tried all the examples I found on stack overflow and none of them work. I managed to make a qliProdListWrapper class and added a "public List qliProdList {get; set;}" that doesn't cause the entire vf page to stop working, but then my list just comes back empty.

In a nutshell, all I want is to be able to generate a list using apex:pageBlockTable of my quote line items where I can display the product name, quote line item quantity and have a commandbutton to remove them from the list. I've been pulling my hair out trying to figure out a way to make this work since the quote line item doesn't store the product's name - I have to fetch the product2 object instance for that using the quote line item's Product2Id field which is a major PITA, but I don't know any other way to get this data.

Please let me know if there's a clean way I can do this

P.S. the quote line items have NOT been inserted yet. This VF page is supposed to display a preview of them before insertion. They only exist as instances of QuoteLineItem(); in my apex controller and have not been inserted yet. There is no way to pull them up with a SOQL query since they would have to be inserted first for that to work.

So again, all I want is an apex:pageBlockTable that displays all the quote line items in my qliList, but I also need it to display product names, which are fields in the related Product2 object, not the quote line item object (hence why I had to write all that extra ugly code to generate qliProdList from the quote line item's product2Id).

Worst case scenario, I could create a formula field in the Quote Line Item object itself that gets the name from the associated Product2 record, but I'd rather do it in the apex controller if possible

1 Answer 1

1

If you had a map of the products, you could display the name that way. Here's the relevant modifications.

Controller

public class MyController {
    public List<QuoteLineItem> qliList { get; set; }
    // Contains products in the quote line items
    public Map<Id, Product2> products { get; set; }
    public MyController() {
        qliList = new List<QuoteLineItem>();
        products = new Map<Id, Product2>();
        // populate qliList ...
        // ... then ...
        Set<Id> productIds = new Set<Id>();
        for(QuoteLineItem item: qliList) {
            productIds.add(item.Product2Id);
        }
        products.putAll([SELECT Name FROM Product2 WHERE Id = :productIds]);
    }
    ...
}

Page

<apex:pageBlockTable id="qliList" value="{!qliList}" var="qliProd" columns="3">
    <apex:column headerValue="Name" value="{!products[qliProd.Product2Id].Name}" />
    <apex:column headerValue="Quantity" value="{!qliProd.Quantity}" />
    <apex:column headerValue="Action">
        <apex:commandButton action="{!delQLI}" rerender="qliList" value="Remove">
            <apex:param name="qliID" value="{!qliProd.Id}"/>
        </apex:commandButton>
    </apex:column>
</apex:pageBlockTable>

Note: When using this technique, make certain that there is a key for each "Product2Id" that is in the map, otherwise you'll get an unrecoverable error regarding a missing key.

9
  • Hi, thanks for the suggestion. I am trying to put my products in a map but I'm getting an "Attempt to de-reference null object" error. I'm running a SOQL query to get the Product2 object for each Product2ID in my qliList, then calling products.put(qli.Product2ID, theproduct); in the controller. The error occurs on the first attempt to call products.put()
    – ag415
    Commented Nov 3, 2017 at 19:27
  • Hi, yeah I just figured that out. I was able to get rid of the error by instantiating it instead of doing public Map<Id, Product2> products {get; set;}. I also had the same issue when trying to do public List<QuoteLineItem> qliList { get; set; } as in your example. I changed that back to public List<QuoteLineItem> qliList = new List<QuoteLineItem>(); as well. Unfortunately now the product names are coming up blank in my visualforce page
    – ag415
    Commented Nov 3, 2017 at 19:30
  • Aha! I just needed to add a getter method for the map, its working now. Thank you for the help! I'll try to refactor this so I'm not running tons of SOQL queries in a loop as per your last suggestion
    – ag415
    Commented Nov 3, 2017 at 19:33
  • 1
    @ag415 Set<Id> productIds = new Set<Id>(); for(QuoteLineItem item: ...) {productIds.add(item.Product2Id); } products = new Map<Id, Product2>([SELECT Name FROM Product2 WHERE Id = :productIds]);
    – sfdcfox
    Commented Nov 3, 2017 at 19:39
  • 1
    @ag415 I've edited this code to hopefully give some clarity to what I'm trying to say. Does this help?
    – sfdcfox
    Commented Nov 3, 2017 at 19:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .