0

I have a visualforce page that I made that loads a table of Registrations (Object Registrant__c) for a particular Enrollee (a Contact on an object called Enrollment).

Then I created a Select list that is populated with a list of Graduation Requirements (Object Graduation_Requirements__c) that are related to the Enrollment that the Registration Contact is a part of.

The end goal is to allow the user to select which Graduation Requirement is equivalent to each of the Registrations the Contact has completed. Then it should store the Graduation Requirement SFID into a field on the Registration Object.

The problem now is that it will only save the value of the Select list from the last row in the table. I understand that a wrapper class may need to be applied somewhere but can't tell where or how.

The visual force page enter image description here

The visual force code

<apex:page standardController="Registrant__c" recordSetVar="unused" sidebar="false" extensions="contactRegistrationList">

<apex:includeScript value="{!$Resource.UtilJS}" />
<apex:form >
  <apex:pageBlock >
    <apex:pageMessages />
    <apex:pageBlock >
      Note: All modifications made on the page will be lost if Return button is clicked without clicking the Save button first. 
    </apex:pageBlock>
    <apex:pageBlockButtons >
      <apex:commandButton value="Save" action="{!saveList}"/>
      <apex:commandButton value="Return" action="{!cancel}"/>
    </apex:pageBlockButtons>
    <apex:pageBlockTable value="{!Records}" var="a" id="table">
      <apex:column headerValue="Id" value="{!a.name}"/>
      <apex:column headerValue="Contact" value="{!a.Contact__c}"/>
      <apex:column headerValue="Event" value="{!a.Associated_Event__c}"/>
      <apex:column headerValue="Section" value="{!a.Section_del__c}"/>
      <apex:column headerValue="Grade" value="{!a.Grade__c}"/>
      <apex:column headerValue="Graduation Requirement Equivalent">
          <apex:selectList value="{!selectedGradReq}" multiselect="false" size="1">
            <apex:selectOptions value="{!gradReqs}"/>
          </apex:selectList>
      </apex:column>
      <apex:column headerValue="Enter amount to credit">
         <apex:inputField value="{!a.Licensure_Credit__c}"/>
      </apex:column>
    </apex:pageBlockTable>
  </apex:pageBlock>
</apex:form>
</apex:page>

And the Apex Class

public class contactRegistrationList { 

    public Registrant__c Registrant {get;set;}     

    public contactRegistrationList(ApexPages.StandardController controller) {
    }

    public List<Registrant__c> Records {get; set;}

    public String selectedGradReq{get;set;}

    public contactRegistrationList(ApexPages.StandardSetController controller){
        controller.AddFields(new List<String>{'Contact__c'});
        Registrant = (Registrant__c) controller.getRecord();     
        Records = new List<Registrant__c>();
        Records = [SELECT id,name,Contact__c,Associated_Event__c,Grade__c,Section_del__c,Licensure_Credit__c,Credited_Date__c,Registration_Date__c,Graduation_Requirement__c FROM Registrant__c WHERE Contact__c = :ApexPages.currentPage().getParameters().get('contactid')]; 
    }

    public List<selectOption> getGradReqs() {
        List<SelectOption> gradReqs=new List<SelectOption>();
        gradReqs.add(new SelectOption('0001', '--Select--'));
        List<Graduation_Requirement__c> gradreqsList=[SELECT Id, Name FROM Graduation_Requirement__c WHERE Enrollment__c =:ApexPages.currentPage().getParameters().get('returl')];
        for(Graduation_Requirement__c r:gradreqsList) {
            gradReqs.add(new SelectOption(r.ID,r.Name));
        }
        return gradReqs;
    }

    public PageReference saveList(){
       // update Records;
        for(Registrant__c r:Records){
          r.Graduation_Requirement__c = selectedGradReq;
        }

        update Records;
        String returnUrl = ApexPages.currentPage().getParameters().get('returl');
        PageReference reRend = new PageReference('/'+ returnUrl);
        reRend.setRedirect(true);
        return reRend;
    }
    public PageReference cancel(){
        String cancelUrl = ApexPages.currentPage().getParameters().get('returl');
        PageReference reRend = new PageReference('/'+ cancelUrl);
        reRend.setRedirect(true);
        return reRend;
    }
}

2 Answers 2

2

I've left the explanation of wrapper classes, and the examples using one to fit your requirement, but I do have to wonder, why don't you use something like:

<apex:selectList value="{!a.Graduation_Requirement__c}" multiselect="false" size="1">
    <apex:selectOptions value="{!gradReqs}"/>
</apex:selectList>

A wrapper class is usually a private inner class, which takes a record as in the constructor, and holds it there, with additional information. This allows you to use this extra data in your controller, or visualforce page.

As an example, lets say you are working on a simple page to select a number of records on this page. To do this without a wrapper class, you would need either a Map<Id, Boolean>, or add another field on the object, such as Visualforce_Selected__c. But what if you also want another field, such as a custom comment? You'll need another map, or another field, and so on.

To avoid this, you can add that extra data to the wrapper class. Below is a full code sample for this example, but lets focus on the important part here.

Each property can be added to this inner class, and will only exist on this data, which wraps a CustomObject__c. You can see it takes a CustomObject__c as a parameter to the constructor, and sets the property Selected, and sets the wrapped record to the record provided.

private class InnerWrapperClass {
    public CustomObject__c Record { get; set; }
    public Boolean Selected { get; set; } // Example Property 

    public InnerWrapperClass(CustomObject__c record) {
        this.Record = record; 
        this.Selected = false; 
    }

}

Using this class means you'll need to be specific about what data you want to operate on- you'll need to call someWrapperReference.Record.Some_Field__c as opposed to someObjectReference.Some_Field__c. You can see this in the visualforce snippet below:

<apex:repeat var="w" value="{!wrapperClass}">
    <apex:input value="{!w.Selected}">
    <apex:input value="{!w.Record.Name}">
</apex:repeat>

In the apex:repeat, both the property on the wrapper class (Selected), as well as a property on the wrapped sObejct (Record.Name) are referenced.


Apex Class

public class YourController {

    public List<InnerWrapperClass> wrapperClass { get; set; }

    public YourController() {
        wrapperClass = new List<InnerWrapperClass>();

        // Add records if you have them 

        List<CustomObject__c> customObjects = [SELECT Id, Name FROM CustomObject__c LIMIT 5];

        for (CustomObject__c c:customObjects) {
            wrapperClass.add(new InnerWrapperClass(c));
        }
    }

    public void Save() {
        List<CustomObject__c> recordsToSave = new List<CustomObject__c>();

        for (InnerWrapperClass w:wrapperClass) {
            if (w.Selected) {
                recordsToSave.add(w.Record);
            }
        }

        update recordsToSave;
    }

    private class InnerWrapperClass {
        public CustomObject__c Record { get; set; }
        public Boolean Selected { get; set; } // Example Property 

        public InnerWrapperClass(CustomObject__c record) {
            this.Record = record; 
            this.Selected = false; 
        }

    }

}

Visualforce

<apex:repeat var="w" value="{!wrapperClass}">
    <apex:input value="{!w.Selected}">
    <apex:input value="{!w.Record.Name}">
</apex:repeat>

To make this example applicable to you, use a List<SelectOption> inside your wrapper class, and provide the values in the constructor. It should look something like:

public InnerWrapperClass(List<SelectOption> options, SomeObject__c record) {
    // .... 
}

You'll need the properties:

public String SelectedOption { get; set; }
public List<SelectOptions> AvaliableOptions { get; set; }
public SomeObject__c Record { get; set; }

And your visualforce will look something like:

<apex:selectList value="{!wrapper.SelectedOption}" multiselect="false" size="1">
    <apex:selectOptions value="{!wrapper.AvaliableOptions}"/>
</apex:selectList>
<apex:column headerValue="Id" value="{!wrapper.Record.Name}"/>

And lastly, you'll have to change your save method:

for(InnerWrapperClass w:Wrappers){
    w.Record.Graduation_Requirement__c = w.SelectedOption;
}
7
  • It's not really an anonymous class. That doesn't exist in Apex.
    – Adrian Larson
    Commented Oct 25, 2016 at 15:38
  • Hi @battery.cord thank you for putting this all together! The problem I have here though is I don't see where in the wrapper class I am creating my list of Registrations, and where I am creating a list of Graduation Requirements for each of the Registrations. Commented Oct 25, 2016 at 18:53
  • Or is the InnerWrapperClass where I do my other SOQL query and grab my Grad Reqs for the select list? Commented Oct 25, 2016 at 19:18
  • You can create a wrapper class which will contain all the attributes of Registrations. After fetching the List from SOQL, you can loop through the list and populate wrapper class instance. This way you can easily traverse the rows and which will help you during save. Commented Oct 25, 2016 at 19:33
  • I've added my new code in the OP, still need help on the select list though, getting it populated. Commented Oct 25, 2016 at 19:58
1

The main problem is in this code saveList():

// update Records;
    for(Registrant__c r:Records){
      r.Graduation_Requirement__c = selectedGradReq;
    }

Even you are selecting the first record, it will assign selected value in the last record.

You can create a wrapper class and use actionFunction to pass the selected value from UI and store it in the wrapper class instance. This way you can store every selected value in each row level.

1
  • Hello Santanu, that's the problem I am aware of and in need of direction, as I keep finding references to adding a wrapper class to solve this but I can't figure out how to do that in combination with what I have now (minus that assignment in the saveList()) Commented Oct 25, 2016 at 15:07

You must log in to answer this question.

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