2. Abstract
• Do you use list view filters?
• Would you like to use that same logic in your Visualforce
pages?
• Don’t reinvent the wheel
• Save time, and make your admin happier as well
3. Nebojsa (Nash) Zgonjanin CRM Developer
• Salesforce MVP (winter 2012),
• Salesforce developer more than 6 years,
• Senior developer (MS .NET) more than
15 years,
• Work for www.OnPath.com, Ottawa,
Ontario, Canada
4. Session Objectives
• StandardSetController and List View Filter Criteria (logic)
• jQuery Table Sort and Visualforce page
• Hierarchy Custom Setting used to control functionality per
org (profile or user level)
• Demo ”Add to Campaigns” of implemented technology
5. Session Objectives
• Short live demo of application to
familiarize audience with topic
• Use of Eclipse to browse code
and point to key moments
• Code in PPT presentation is used
as reference
6. Solution Intro I
• StandardSetController and List View Filter Criteria
• Define StandardSetController (SOQL query)
• Apply Filter Criteria from List View to StandardSetController
• Execute SOQL and use in Apex code
7. Solution Intro II
jQuery Table Sort and Visualforce Page
• jQuery Setting
• Static resources
• <apex:includeScript>
• Mash up of:
• standard HTML table tags
• <apex:repeat> tag
• jQuery <script> code
8. Solution Intro III
Hierarchy Custom Settings (Levels of use)
• Org default
• Profile (group of users)
• User (individual)
• Use of setting values in Apex code
• Use of setting values in Visual Force page
• Demo: User (Serbian) vs. Org Default (English)
9. Nash
Code sample (package) available here:
https://github.com/nzgonjanin/Dreamforce2012
Thank You
11. Solution intro
I always wanted to leverage platform functionality and add
more of client side functionality that browser bring in game.
Combination of APEX controller extension and standard
controllers (ApexPages.StandardController and
ApexPages.StandardSetController) give me option to leverage standard
platform functionality and add more flexibility and user interface
functionality to Visual Force page using jQuery Table sorter
(jquery.tablesorter.min.js) add on, that enable sorting of multiple
columns.
Using Custom setting I made available different set of
parameters to be used per Org; Profile or User (labels, list views for
filtering, Error Messages…) that enable easy internationalization if
needed.
12. Objectives and Solution I
What is the Add to Campaigns app
Salesforce.com provides features for adding many people to a
single campaign, but what about an organization that manages
multiple, ongoing campaigns like newsletters, customer programs,
annual events, and even holiday card lists?
Manually adding a single person to multiple campaigns one by
one is a pain, and contributes to poor adoption, and incomplete or
unusable data.
This app application in salesforce.com allows users to add a
single contact or lead to multiple campaigns with as few clicks as
possible.
13. Objectives and Solution II
There are two portions to this application: end-user and administrator (non-developer).
NOTE: Custom Settings, Standard List View filter, Standard Controller,
StandardSetController are used to give end user (administrator) flexibility to manage data
set used for app in combination with visual force page
ADDTOCAMPAIGNS_LISTVIEWFILTER or using standard List View management under
Campaigns tab.
The end-user portion of the application works the same for both contacts and
leads. Add a custom button to the Campaign History related list for both Leads and
Contacts called "Add to Campaigns". When the end-user clicks this button display a list of
campaigns with check boxes and a "check all" option. (The query for the list of campaigns
will be determined in the administrator portion of the application.) When the end-user
submits the form, insert the contact/lead to the campaign as member with the default
status for that campaign and return the user back to the standard contact/lead details
page.
14. APEX controller extension
(addtocampaigns_Extension.cls I )
public with sharing class addtocampaigns_Extension {
//variables used on Visual force page for interaction with end user
public Lead ParticipantLead {get; set;} //Lead record returned based on Id (pid) query parameter from custom button
public Contact ParticipantContact {get; set;} //Contact record returned based on Id (pid) query parameter from custom
button
public string ParticipantId {get;set;} //Value of Query parameter pid
public list<addtocampaigns_Wrapper> Campaign_List=new list<addtocampaigns_Wrapper>(); //List of campaign records
to be used for selection
public Boolean SubmitDisabled {get;set;} //[Submit] button and [Select All] button can be used just ones
public AddtoCampaignsSetting__c mySetting {get; set;} //Custom Setting for logged user
public addtocampaigns_Extension(ApexPages.StandardController controller) {
//Standard controller extensin used to add custom functionality to visual force page
ParticipantId=System.currentPageReference().getParameters().get('pid');
mySetting=AddtoCampaignsSetting__c.getInstance();//Custom Setting Definitions
getParticipant(); //get Participant data from Lead or Contact
getCampaign_List();//get list for campaign selection
}
15. APEX controller extension
public ApexPages.StandardSetController con {
(addtocampaigns_Extension.cls II)
//Standard Set controller used to add custom functionality to visual force page
//and leverage standard behavior of List View filters
get {
if(con == null) {
//Standard set controller query used to retrieve data from Campaign object
//used on visual force page to select potential campaigns
integer myLimit=integer.valueOf(mySetting.RecordSet_Limit__c);
if (myLimit==null){
myLimit=200;
}
con = new ApexPages.StandardSetController(Database.getQueryLocator(
[Select Id, Name, StartDate,EndDate, Type, Status, ParentId, RecordTypeId
FROM Campaign
order By Name,StartDate
limit :myLimit]));
//in order to use it again you need to refresh page or go back to participant and start again
//set filter id that is applied for Hierarchy setting Org/Profile/User
if (mySetting.ListViewId__c!=null){
//Filter Magic is heppening here
con.setPageSize(myLimit);
con.setFilterID(mySetting.ListViewId__c);
}
}
return con;
}
set;
}
16. APEX controller extension
//Queried data set is used to laverage data set
(addtocampaigns_Extension.cls III)
public List<addtocampaigns_Wrapper> getCampaign_List() {
//get list for campaign selection
if (Campaign_List.Size()==0){
//Load campign list just ones on first page load
//(List<Campaign>)con.getRecords()) will execute query and
//apply defined mySetting.ListViewId__c as filter to set of records
for (Campaign camp: (List<Campaign>)con.getRecords()){
Campaign_List.add(new addtocampaigns_Wrapper(camp));
//check if participant is already part of campaign and disable it for selection
if (ParticipantId.startsWith('00Q')){
//process lead campaign member records
for (CampaignMember CM :ParticipantLead.CampaignMembers){
if (CM.CampaignId==camp.Id && Campaign_List.Size()>0){
//disable check box on visual force page
Campaign_List[Campaign_List.size()-1].disabled=true;
break;
}
}
}else{
//process contact campaign member records
for (CampaignMember CM :ParticipantContact.CampaignMembers){
if (CM.CampaignId==camp.Id && Campaign_List.Size()>0){
//disable check box on visual force page
Campaign_List[Campaign_List.size()-1].disabled=true;
break;
}
}
}
}
}
return Campaign_List;
}
17. Addtocampaigns_Wrapper.cls
(used in APEX controller extension to support app functionality)
public with sharing class addtocampaigns_Wrapper {
//variables used for creating add to Campaigns record
public String message{ get; set; } //success message
public Boolean checked{ get; set; } //check box for selection
public Boolean disabled {get; set;} //if member is alread part of campaign selection check box is disabled
public Campaign camp { get; set;} //Campaign record returned as part of data set driven by listView filter
public addtocampaigns_Wrapper(){
//constructor without passed parameters
camp = new Campaign();
checked = false;
disabled = false;
message='';
}
public addtocampaigns_Wrapper(Campaign c){
//constructor with passed parameters
camp = c;
checked = false;
disabled = false;
message='';
}
}//end of class
21. Visual Force Page code overview
(addtocampaigns.page III)
//standard HTML table tags used with apex:repeat tag to obtain data set
<table id="myTable" class="tablesorter">
<thead> //table headers
<tr>
<th>{!$Setup.AddtoCampaignsSetting__c.column_Select_Header__c}</th>
<th>{!$Setup.AddtoCampaignsSetting__c.column_Name_Header__c}</th>
<th>{!$Setup.AddtoCampaignsSetting__c.column_StartDate_Header__c}</th>
<th>{!$Setup.AddtoCampaignsSetting__c.column_EndDate_Header__c}</th>
<th>{!$Setup.AddtoCampaignsSetting__c.column_Type_Header__c}</th>
<th>{!$Setup.AddtoCampaignsSetting__c.column_Status_Header__c}</th>
<th>Parent</th>
<th>Record Type</th>
</tr>
</thead>
<tbody> //table rows (data set from list view)
<apex:repeat value="{!Campaign_List}" var="Camp" id="theRepeat">
<tr>
<td> <apex:inputCheckbox id="Selected" value="{!Camp.checked}" disabled="{!Camp.disabled}"/></td>
<td> <apex:outputField id="Name" value="{!Camp.Camp.Name}"/></td>
<td> <apex:outputField id="StartDate" value="{!Camp.Camp.StartDate}"/></td>
<td> <apex:outputField id="EndDate" value="{!Camp.Camp.EndDate}"/></td>
<td> <apex:outputField id="Type" value="{!Camp.Camp.Type}"/></td>
<td><apex:outputField id="Status" value="{!Camp.Camp.Status}"/></td>
<td><apex:outputField id="Parent" value="{!Camp.Camp.ParentId}"/></td>
<td><apex:outputField id="RecordType" value="{!Camp.Camp.RecordTypeId}"/></td>
</tr>
22. Custom Setting Hierarchy type overview
Hierarchy Custom Settings: A type of custom setting that uses a built-in hierarchical logic that lets you “personalize” settings for specific profiles or users. The hierarchy logic
checks the organization, profile, and user settings for the current user and returns the most specific, or “lowest,” value. In the hierarchy, settings for an organization are
overridden by profile settings, which, in turn, are overridden by user settings.
https://na14.salesforce.com/help/doc/user_ed.jsp?loc=help&target=cs_manage_data.htm§ion=integrate