0

I'm creating a VF page on Opportunity Products where I have an apex:repeat and inside the repeat, I have a picklist that gets it's values from a SOQL query on a related object. I have no problem populating that list but what I can't figure out is how get the values out of every picklist inside the repeat into my controller method and update the original record with those values.

For example, I want Opportunity Product[0] to have its' competitor set as the value from the picklist besides that product name, Opportunity Product[1] with that value etc. Here, competitors are fetched with SOQL query to a custom object. To map the values correctly, that's where I'm stumped. Would using a Map be efficient, where id put into the map the OpportunityProductId and competitor value so I can map the selected value from the picklist to the correct product?

Controller:

Page:

<apex:page controller="VF_compList">
<apex:form >  
<apex:pageBlock >
<table>
    <th>Product name</th><th>Competitor</th>
<div align="left">    
<apex:repeat value="{!products}" var="prods" rendered="true">
<tr>
<div align="left">
 <apex:outputText value="{!prods.name}" id="theValue"/><br/>
</div>
<div align="right">
<apex:selectList id="dropdown"  multiselect="false" size="1"> 
<apex:selectOptions value="{!Competitors}">
</apex:selectOptions>
</apex:selectList>
</div>
</tr>
</apex:repeat>
    </div>
    </table>
</apex:pageBlock>
<apex:commandButton action="{!submit}" id="theButton"/>
</apex:form>
</apex:page>

controller:

public class VF_compList {


public VF_compList(){}

public Id gId = ApexPages.currentPage().getParameters().get('gId');


Opportunity o = [SELECT id from Opportunity where Id =:gId];

Map<Id,String> prodMap = new Map<Id,String>();



public List<SelectOption> comps {get;set;} 
public List<OpportunityLineItem> olist {get;set;}
public List<Opportunity_Competitor__c> competitorsList {get;set;}
String[] tempstring {get;set;}

public void setCompetitorsOnKeyup(){

}

public List<SelectOption> getCompetitors(){
system.debug('gId is: '+gId);
competitorsList = [SELECT Name, Competitor__r.Name from 
Opportunity_Competitor__c where Opportunity__c =:o.Id];
List<SelectOption> values = new List<SelectOption>();
for(Opportunity_Competitor__c a:competitorsList){
    SelectOption b = new 
SelectOption(a.Competitor__r.Name,a.Competitor__r.Name);
    values.add(b);
    //comps.add(b);
}    
return values;

}

public List<OpportunityLineItem> getProducts(){
olist = [SELECT Id, Name,txCompetitors__c from OpportunityLineItem where 
OpportunityId =:o.Id];
return oList;

}

public void submit(){
    for(OpportunityLineItem e:olist){
        //e.txCompetitors__c = ?
    }
}   

}
1

In all but the most unusual scenarios, it is generally advisable to put the ID value for the first parameter of your SelectOption. This gives you the automatic mapping you're looking for without any extra effort:

competitorsList = [SELECT Name, Competitor__c, Competitor__r.Name from 
Opportunity_Competitor__c where Opportunity__c = :o.Id];
List<SelectOption> values = new List<SelectOption>();
for(Opportunity_Competitor__c a:competitorsList){
    SelectOption b = new 
SelectOption(a.Competitor__c,a.Competitor__r.Name);
    values.add(b);
    //comps.add(b);
}    
return values;

<apex:selectList value="{!lineitem.txCompetitors__c}" id="dropdown"  multiselect="false" size="1"> 

Please note that getCompetitors right now is essentially a query inside of a loop, and may cause your code to crash from too many SOQL queries. At minimum, you should cache the results to avoid this problem:

transient List<SelectOption> competitorsOptions;
public List<SelectOption> getCompetitors(){
    if(competitorsOptions == null) {
        competitorsList = [SELECT Name, Competitor__c, Competitor__r.Name from 
        Opportunity_Competitor__c where Opportunity__c = :o.Id];
        competitorsOptions = new List<SelectOption>();
        for(Opportunity_Competitor__c a:competitorsList){
            SelectOption b = new 
                SelectOption(a.Competitor__c,a.Competitor__r.Name);
            competitorsOptions.add(b);
        }
    }
    return values;
}

Also, you're going to need to initialize your list of opportunity line items so that you can edit them. This answer presumes that you've changed your code so that you can bind your inputs to the line items you're creating.

  • Thanks sfdcfox, I didn't realize that I could just bind the line item Id to to the picklist and then use that to update the line items. – akarnid Sep 21 '18 at 15:49
  • I'm still stuck on this. public void submit(){ List<OpportunityLineItem> submitList = new List<OpportunityLineItem>(itemlist); for(OpportunityLineItem e:itemlist){ for(SelectOption b:values){ e.txCompetitors__c = b.getValue(); } submitlist.add(e); } try{update submitList;} catch(Exception e){system.debug('+++Exception e: '+e.getMessage());} } This line here is a null pointer -> for(SelectOption b:values){ . Isn't it enough to declare it public? – akarnid Oct 8 '18 at 9:59
  • @akarnid the first loop-in-a-loop makes no sense. The values are already bound to the record directly, so you don't need the selectoption list at all. – sfdcfox Oct 8 '18 at 14:07
  • OK, I just don't quite understand how I map from the selected picklist value to the corresponding field on the OpportunityLineItem. Since i'm inside an <apex:repeat> tag for both the line items and the competitor dropdown does the Salesforce platform automatically provide the mapping to the correct record? – akarnid Oct 8 '18 at 14:29
  • @akarnid Yes, it's in the field already, that's how we bound the data. – sfdcfox Oct 8 '18 at 14:31

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.