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

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.

  • 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 Nov 3 '17 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 Nov 3 '17 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 Nov 3 '17 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 Nov 3 '17 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 Nov 3 '17 at 19:58

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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