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 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;
}
}
Best Answer
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:
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 asVisualforce_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 aCustomObject__c
as a parameter to the constructor, and sets the propertySelected
, and sets the wrapped record to the record provided.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 tosomeObjectReference.Some_Field__c
. You can see this in the visualforce snippet below: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
Visualforce
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:You'll need the properties:
And your visualforce will look something like:
And lastly, you'll have to change your save method: