You need to sign in to do that
Don't have an account?
MC2014
blockTable not displaying quantity from a wrapper class.
I borrow a good part of michalforce receipe (http://www.michaelforce.org/recipeView?id=a0G30000006eVxVEAU) and used this shopping cart code work with creating a case.
So whenever, I added a new product to the shopping cart, the quantity doesn't get saved. The quantity is stored in a wrapper class, and if system.debug upon saving it shows that PricebookEntry object and quantity is in the "shoppingCart2" wrapper list, somehow {!s.productQuantity} in VF isn't being pulled.?
Here is the entire Apex:
The portion of VF that where quantity should be displaying:
This is the entire VF page:
So whenever, I added a new product to the shopping cart, the quantity doesn't get saved. The quantity is stored in a wrapper class, and if system.debug upon saving it shows that PricebookEntry object and quantity is in the "shoppingCart2" wrapper list, somehow {!s.productQuantity} in VF isn't being pulled.?
Here is the entire Apex:
public with sharing class InternalFurfillment2 { public String searchString {get;set;} private List<PriceBookWrapper> forDeletion2 = new List<PriceBookWrapper>(); public List<PriceBookWrapper> shoppingCart2 {get;set;} public priceBookEntry[] AvailableProducts {get;set;} public String toSelect {get; set;} public String toUnselect {get; set;} public Boolean overLimit {get;set;} public string priceBookName = 'Internal Price Book'; private ApexPages.StandardController stdController; private Case caseObject; public InternalFurfillment2(ApexPages.StandardController controller) { this.caseObject = (Case) controller.getRecord(); shoppingCart2 = new List<PriceBookWrapper>(); updateAvailableList(); } public void updateAvailableList() { // We dynamically build a query string and exclude items already in the shopping cart String qString = 'select Id, Pricebook2Id, IsActive, Product2.Name, Product2.Family, Product2.IsActive, Product2.Description, UnitPrice, Product2.Vendor__c from PricebookEntry where IsActive=true and PricebookEntry.Pricebook2.Name = \'' + priceBookName + '\''; system.debug('qString begin==>' + qString); // note that we are looking for the search string entered by the user in the name OR description // modify this to search other fields if desired if(searchString!=null){ qString+= ' and (Product2.Name like \'%' + searchString + '%\' or Product2.Description like \'%' + searchString + '%\')'; } Set<Id> selectedEntries = new Set<Id>(); for(PriceBookWrapper d : shoppingCart2){ system.debug('d==>' + d); selectedEntries.add(d.pbeEntry.Id); } system.debug('selectedEntries==>' + selectedEntries); if(selectedEntries.size()>0){ String tempFilter = ' and Id not in ('; for(Id i : selectedEntries){ tempFilter+= '\'' + (String)i + '\','; } String extraFilter = tempFilter.substring(0,tempFilter.length()-1); extraFilter+= ')'; qString+= extraFilter; } qString+= ' order by Product2.Name'; qString+= ' limit 101'; system.debug('qString:' +qString); AvailableProducts = database.query(qString); // We only display up to 100 results... if there are more than we let the user know (see vf page) if(AvailableProducts.size()==101){ AvailableProducts.remove(100); overLimit = true; } else{ overLimit=false; } } public void addToShoppingCart(){ system.debug('AvailableProducts==>' + AvailableProducts); system.debug('shopping cart outside top==>' + ShoppingCart2); // This function runs when a user hits "select" button next to a product for(PricebookEntry d : AvailableProducts){ if((String)d.Id==toSelect){ shoppingCart2.add(new PriceBookWrapper(d,0)); system.debug('shopping cart inside==>' + ShoppingCart2); break; } }system.debug('shopping cart outside==>' + ShoppingCart2); updateAvailableList(); } public PageReference removeFromShoppingCart(){ // This function runs when a user hits "remove" on an item in the "Selected Products" section Integer count = 0; for(PriceBookWrapper d : shoppingCart2){ if((String)d.pbeEntry.Id==toUnselect){ if(d.pbeEntry.Id!=null) forDeletion2.add(d); shoppingCart2.remove(count); break; } count++; } updateAvailableList(); return null; } public PageReference onSave(){ system.debug('shoppingCart2 submit==>' + shoppingCart2); return null; } public class PriceBookWrapper{ public Integer productQuantity {get;set;} public PriceBookEntry pbeEntry {get;set;} public PriceBookWrapper(PriceBookEntry pbeEntry, Integer productQuantity){ this.pbeEntry = pbeEntry; this.productQuantity = productQuantity; } } }
The portion of VF that where quantity should be displaying:
.. <apex:pageBlock title="My Content"> <apex:outputPanel id="mainBody"> <!-- this is the upper table... a.k.a. the "Shopping Cart"--> <!-- notice we use a lot of $ObjectType merge fields... I did that because if you have changed the labels of fields or objects it will reflect your own lingo --> <apex:pageBlockSection title="{!$ObjectType.Product2.LabelPlural} Selection" id="selected" columns="1"> <apex:pageBlock title="Selected {!$ObjectType.Product2.LabelPlural}" id="selected"> <apex:pageblockTable value="{!shoppingCart2}" var="s"> <apex:column > <apex:commandLink value="Remove" action="{!removeFromShoppingCart}" reRender="selected,searchResults" immediate="true"> <!-- this param is how we send an argument to the controller, so it knows which row we clicked 'remove' on --> <apex:param value="{!s.pbeEntry.Id}" assignTo="{!toUnselect}" name="toUnselect"/> </apex:commandLink> </apex:column> <apex:column headerValue="{!$ObjectType.Product2.LabelPlural}" value="{!s.pbeEntry.Product2.Name}"/> <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Quantity.Label}"> <apex:inputText value="{!s.productQuantity}" style="width:70px" required="true" onkeyup="refreshTotals();"/> </apex:column> <!-- --> <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Description.Label}"> <apex:outputField value="{!s.pbeEntry.Product2.Family}"/> </apex:column> </apex:pageblockTable> </apex:pageBlock> ...
This is the entire VF page:
<apex:form> <apex:pageBlock title="My Content"> <apex:outputPanel id="mainBody"> <apex:pageBlockSection title="{!$ObjectType.Product2.LabelPlural} Selection" id="selected" columns="1"> <apex:pageBlock title="Selected {!$ObjectType.Product2.LabelPlural}" id="selected"> <apex:pageblockTable value="{!shoppingCart2}" var="s"> <apex:column > <apex:commandLink value="Remove" action="{!removeFromShoppingCart}" reRender="selected,searchResults" immediate="true"> <!-- this param is how we send an argument to the controller, so it knows which row we clicked 'remove' on --> <apex:param value="{!s.pbeEntry.Id}" assignTo="{!toUnselect}" name="toUnselect"/> </apex:commandLink> </apex:column> <apex:column headerValue="{!$ObjectType.Product2.LabelPlural}" value="{!s.pbeEntry.Product2.Name}"/> <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Quantity.Label}"> <apex:inputText value="{!s.productQuantity}" style="width:70px" required="true" onkeyup="refreshTotals();"/> </apex:column> <!-- --> <apex:column headerValue="{!$ObjectType.OpportunityLineItem.Fields.Description.Label}"> <apex:outputField value="{!s.pbeEntry.Product2.Family}"/> </apex:column> </apex:pageblockTable> </apex:pageBlock> <!--this is the lower table: search bar and search results--> <apex:pageBlock > <apex:outputPanel styleClass="search"> Search for {!$ObjectType.Product2.LabelPlural}: </apex:outputPanel> <apex:actionRegion renderRegionOnly="false" immediate="true"> <apex:actionFunction name="fetchResults" action="{!updateAvailableList}" reRender="searchResults" status="searchStatus"/> <!-- here we invoke the scripting to get out fancy 'no button' search bar to work --> <apex:inputText value="{!searchString}" onkeydown="if(event.keyCode==13){this.blur();}else{resetTimer();}" style="width:300px"/> <i> <!-- actionStatus component makes it easy to let the user know when a search is underway --> <apex:actionStatus id="searchStatus" startText="searching..." stopText=" "/> </i> </apex:actionRegion> <br/> <br/> <apex:outputPanel id="searchResults"> <apex:pageBlockTable value="{!AvailableProducts}" var="a"> <apex:column headerValue="{!$ObjectType.Product2.Fields.Name.Label}" value="{!a.Product2.Name}" /> <apex:column headerValue="{!$ObjectType.Product2.Fields.Family.Label}" value="{!a.Product2.Family}"/> <apex:column headerValue="{!$ObjectType.Product2.Fields.Description.Label}" value="{!a.Product2.Description}"/> <apex:column > <!-- command button in a column... neato --> <apex:commandButton value="Select" action="{!addToShoppingCart}" reRender="selected,searchResults" immediate="true"> <!-- again we use apex:param to be able to tell the controller which row we are working with --> <apex:param value="{!a.Id}" assignTo="{!toSelect}" name="toSelect"/> </apex:commandButton> </apex:column> </apex:pageBlockTable> <!-- We put up a warning if results exceed 100 rows --> <apex:outputPanel styleClass="fyi" rendered="{!overLimit}"> <br/> Your search returned over 100 results, use a more specific search string if you do not see the desired {!$ObjectType.Product2.Label}. <br/> </apex:outputPanel> </apex:outputPanel> </apex:pageBlock> </apex:pageBlockSection> </apex:outputPanel> <apex:pageBlockSectioncolumns="1"> <apex:outputPanel layout="block" style="align: center"> <apex:commandButton action="{!onSave}" value="Save"/> </apex:outputPanel> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page>
I think the actual problem is that the SELECT Link on the page has its immediate attribute set to true.
Please remove the immediate attribute and then try the code.
<apex:commandButton value="Select" action="{!addToShoppingCart}" reRender="selected,searchResults" > - No need of immediate attribute
Thanks,
Kaustav
All Answers
I think the actual problem is that the SELECT Link on the page has its immediate attribute set to true.
Please remove the immediate attribute and then try the code.
<apex:commandButton value="Select" action="{!addToShoppingCart}" reRender="selected,searchResults" > - No need of immediate attribute
Thanks,
Kaustav
My first version of my form had multi select drop-down, so only way for me to get quantity and the price book id for all the items user have selected is to do a wrapper.
So if I were to just assign price book back in the constructor, how would I suppose to keep track of quantity they've enter?
Yes, on save doesn't do anything because I remove the logic for this post because it is not related, other than to show that the information are in the wrapper variable.
Kaustav,
removed the immediate, hitting the select button won't add anything to the cart.
Controller:
VF Page:
Please let us know if it works.
Thanks,
Kaustav
Your original post does resolve this, its just that I had a require field some where on the form that I had missed.
Thanks.
<apex:commandButton value="Select" action="{!addToShoppingCart}" reRender="selected,searchResults" > - No need of immediate attribute