I currently have a Visualforce page embedded on the contact record that displays all active campaigns with a chexckbox indicating if the contact is a member of the campaign (if checked then the contact is a member). I also have a command button to save changes. The visualforce code is generated using an apex:repeat like as so:
<apex:repeat value="{!campaignWrappers}" var="cm"> <div class="MailingRow"> <apex:outputText styleClass="CampaignLabel" value="{!cm.c.Name}" ></apex:outputText> <apex:inputCheckbox styleClass="CampaignCheck" value="{!cm.selected}" /> </div> </apex:repeat>
My question is, what is the best way to go about passing the checkbox values to the controller? Ideally I would like to pass across only checkboxes that have been changed, passing across a list of those that have been gone from checked to unchecked and a second list that contains the checkboxes that have gone from unchecked to checked. I can then insert and delete these lists.
Is this a case where an actionSupport tag should be used on the checkbox?
<apex:actionSupport event="onChange" action="{!updateChangeList}" />
Whole collection will be sent back to the server (so state of all checkboxes). That's not too different between Salesforce and any other web-related language (see Get $_POST from multiple checkboxes for example. Main difference is that usually you'd use a variable with name ending in []
and SF will use unique names with incrementing number somewhere in the name).
If you really want to build 2 lists - maybe some javascript magic of adding/removing content of 2 hidden text fields... but that's bit messy.
When the form will be submitted and your updateChangeList()
gets called you could iterate the collection of CampaignWrappers and compare with previous value. Either store the previous value in 1 more variable in the wrapper & not expose it to the user or you'll still know based on what was in the Campaign:
Set<Id> campaignsToBeAddedTo = new Set<Id>();
Set<Id> campaignsToBeRemovedFrom = new Set<Id>();
for(CampaignMember cm : campaignWrappers){
if(cm.selected && cm.c.CampaignMembers.isEmpty(){
// is ticket but wasn't a member before
campaignsToBeAddedTo.add(cm.c.Id);
} else if (!cm.selected && !cm.c.CampaignMembers.isEmpty()){
// not ticked but used to be a member
campaignsToBeRemovedFrom.add(cm.c.Id);
}
}
You could even optimize it a bit (like put isEmpty() checks to helper variable). Or read about setter methods that can have "side effects". After all a loop like that will be run for you anyway when form data will be deserialized. http://blogs.developerforce.com/developer-relations/2008/06/property-access.html is a nice starting point (it's ancient, I know. Basically before this blog post we had to write Boolean getSelected()
and void setSelected(Boolan b)
for each variable we wanted to use in VF).
last but not least - a link to page execution order.