Customized search and selection (Add multiple child records at one go)

9:08 PM

Scenario:


You want your users to be able to make a customized search and not the way salesforce searches. You also would like to allow your users to select multiple records from the search results and process them.

If the user does not select any record and clicks on the Next button you want to display an Error Message asking him to select at least one record to proceed.


Tip: You may be aware that salesforce allows only one child to be added to a parent at a time. Even though some wizards allow you to mass assign child records to a parent, this is not available for all objects. Modifying this code, you can achieve the functionality of selecting many child records and assigning them to a parent at one click!!!


The screenshots below clearly expresses the scenario...

Before search..



After search...



Note:

The following code searches for contacts based on the user inputs. Customize it as needed for your needs. Also, this code is called from a custom button on the Campaign Page Layout.


Javascript function :

We also make use of a javascript function to select all records at one go.
The code has suffecient comments to describe about each and every functionality. Do you think you need more info, then feel free to post your comment.

How to use this code?

  • Save the "Apex Class" first. Save the Visualforce page next.
  • Create a custom button in Campaign, select the source as "Visualforce Page" and select the visualforce page just now saved.
  • Go to PageLayout and add your newly created custom button to this layout.
  • Click on any Campaign Record, go to the detail page and then click on the custom button to view the page created.
Visualforce code:
<apex:page standardcontroller="Campaign" extensions="MassEmailFromCampaign" >
<!-- Javascript function to check all rows in the table -->
<script>
function checkAll(cb)
{
var inputElem = document.getElementsByTagName("input");
for(var i=0;i<inputElem.length;i++)
{
if(inputElem[i].id.indexOf("selectLine1")!=-1)
inputElem[i].checked = cb.checked;
}
}
</script>
<!-- End of Javascript function -->
<apex:form >
<apex:sectionHeader title="Step 1" subtitle="Select Contacts to send Email"/>
<apex:pageblock >
<apex:pageBlockSection title="Search Contacts" columns="1"></apex:pageBlockSection>

<!-- Div to give a colored box effect -->

<div style="border-width:2px;border-style:solid;border-color:orange;">

<!-- Panel grid to display boxes o accept user input values -->
<apex:panelGrid columns="2">
<apex:outputLabel style="font-weight:bold;" value="Contact E-mail" ></apex:outputLabel>
<apex:inputText value="{!userinput}"/>
<apex:outputLabel style="font-weight:bold;" value="Contact Name" ></apex:outputLabel>
<apex:inputText value="{!userinp}"/>
</apex:panelGrid>
<!-- End of panelgrid -->
<!-- Div to position the commandbutton appropriately -->
<div style="position:relative;left:75px;">
<apex:commandButton value="Search" action="{!contactsearch}" />
</div>
<!-- End of div -->
<br/>
</div>

<!-- End of colored box div -->
<br/>
<!-- Display error message -->
<apex:pagemessage strength="2" title="Error!!" severity="error" detail="Please select a contact or enter email address to proceed" rendered="{!errormsg}"/>
<!-- End of error message -->

<!-- Display search results -->
<apex:pageblocksection columns="1" title="Search results" rendered="{!NOT(ISNULL(results))}" >
<apex:outputpanel id="Contactlist">

<apex:pageBlockTable value="{!results}" var="contacts">
<apex:column >
<apex:facet name="header">
<apex:inputCheckbox onclick="checkAll(this)"/>
</apex:facet>
<apex:inputCheckbox value="{!contacts.selected}" id="selectLine1"/>
</apex:column>
<apex:column headervalue="Contact Name">
<apex:outputtext value="{!contacts.con.Name}"/>
</apex:column>
<apex:column headervalue="Account Name">
<apex:outputtext value="{!contacts.con.Account.Name}"/>
</apex:column>
<apex:column headervalue="Title">
<apex:outputtext value="{!contacts.con.Title}"/>
</apex:column>
</apex:pageBlockTable> <br/><br/>

</apex:outputpanel>
</apex:pageblocksection>
<!-- End of search results -->

<!-- Commandbutton to proceed to next screen -->
<div style="position:relative;left:75px;">
<apex:commandButton value="Next" action="{!processSelected}"/>
<apex:commandbutton value="Cancel" action="{!Cancel}"/>
</div>
<!-- End of Commandbutton -->
</apex:pageblock>
</apex:form>
</apex:page>
The Apex code for this page will be...

public class MassEmailFromCampaign {

/* Constructor Function. The campaign id is captured in this function */
public MassEmailFromCampaign(ApexPages.StandardController controller)
{
cid=System.currentPageReference().getParameters().get('id');
}
/* Variable declarations */

Public String cid; // Stroes Campaign Id
public List<cContact> contactList {get; set;} // Wrapper class which stores contact data and a boolean flag.
public Boolean selectAllCheckbox {get; set;} // Stores checkbox data.
public boolean errormsg=false; // Error msg. When no contact has been selected.
String userinput; // Contact Email
String userinp; // Contact Name

Public boolean displayboxes;

Public List<Contact> results = new List<Contact>(); // Contact search results.
Public List<Contact> selectedContactsstep2 = new List<Contact>(); // Selcted Contacts


/* End of Variable declarations */

/* Getter and setter methods for getting the user input ie. Contact name and email from the UI */

public String getuserinput(){return userinput;}
public void setuserinput(String userinp){this.userinput=userinp;}
public String getuserinp(){return userinp;}
public void setuserinp(String userinp){this.userinp=userinp;}


/*End of Getter and Setter methods */



/* Method to Search the contact database to fetch the query results */
public List<Contact> contactsearch()
{
errormsg=false;
contactList = new List<cContact>();
for(Contact c : [select Account.Name,Name,FirstName,LastName,Email,title,Id from Contact where Email like :userinput+'%' and Name like :userinp+'%'])
{
contactList.add(new cContact(c));
}

return null;
}
/* End of method */


/* Method for returning the contact search results to the UI */
public List<cContact> getresults()
{

return contactList;

}
/* End of Method */


/* Wrapper class to contain contact record and a boolean flag */
public class cContact
{
public Contact con {get; set;}
public Boolean selected {get; set;}

/*This is the contructor method. When we create a new cContact object we pass a
Contact that is set to the con property. We also set the selected value to false*/
public cContact(Contact c)
{
con = c;
selected = false;
}
}
/* end of Wrapper class */


/* Method to fetch the selected records and send email to them */
public PageReference processSelected()
{

List<Contact> selectedContacts = new List<Contact>();
if (contactList!= null)
{
for(cContact cCon : getresults()){
if(cCon.selected == true){
selectedContacts.add(cCon.con);
}
}

selectedContactsstep2=selectedContacts;
}
/* return error message if no contact is selected */
if (selectedcontacts.size()==0)
{
errormsg=true;
return null;
}
else
{
errormsg=false;
String id=System.currentpagereference().getparameters().get('id');
Pagereference p=new Pagereference ('/apex/MassEmailFromCampaignStep2');
return p;
}

}
public List<SelectOption> getItems()
{
List<SelectOption> options = new List<SelectOption>();
options.add(new SelectOption('YES','YES'));
options.add(new SelectOption('NO','NO'));
return options;
}


/* return error message if no contact is selected */
public boolean geterrormsg()
{
return errormsg;
}


/* Method to cancel the entire process */
public Pagereference Cancel()
{
Pagereference p =new Pagereference('/'+cid);
return p;
}


}
Note that, "selectedcontacts" is the variable which holds the contacts you have selected. Use this for further processing. I have just redirected to another visualforce page, you can do your own stuff...

Post your queries....

19 comments

  1. Great extension of the code at http://wiki.developerforce.com/index.php/Wrapper_Class. Thanks for showing a super way to improve it!
    But please cite your sources. :)

    ReplyDelete
  2. Sure David... Will add a references section in my upcoming aticles.. Thanks for the suggestion..

    ReplyDelete
  3. Thanks for posting - I found this to be easy to follow and adapt :-)

    Have you got a simple example of how to use the 'selectedcontacts'? I've adapted this example to select a list of contacts to associate to a custom object via a junction object (contact_callreport) but I'm now searching the internet for an example of how to do the association. Any pointers appreciated.

    ReplyDelete
  4. Thanks for your feedback Ken...

    If you have to insert records into the junction object i guess each record should have the custom object Id and the contact Id.. will let you know if i find any pointers....

    And thanks once again for suggesting a topic for my next article :-) "How to insert records into Junction Object"

    ReplyDelete
  5. This is great. Can you also please guide me through how to add multiple child records to the parent record at a time

    ReplyDelete
  6. This is great. Can you also please guide me through how to add multiple child records to the parent record at a time

    ReplyDelete
  7. Hello Venu, in the example above the "selectedcontacts" variable holds all the contacts selected... Say you want to add all these contacts to a given account, then loop through the "selectedcontacts" list and populate the field AccountId with the ID of the desired account.. Likewise for relationship to other objects

    ReplyDelete
  8. Did you end up doing the article on "How to insert records into Junction Object"?

    Do you have any code samples of how to loop through the "selectedcontacts" and upsert the records?

    ReplyDelete
  9. getting error in eclipse that this code is dirty, while saving class to server... please help

    ReplyDelete
  10. Hey.. can you please provide the next step for this. for emailing the contacts..

    Thanks

    ReplyDelete
  11. sir how to put an calendar through visual force

    ReplyDelete
  12. How to search for records without using JavaScript.....Please help!!!

    ReplyDelete
  13. Is there a way to make the input text for firstname & lastname take both user input values as well as pre-populated firstname & lastname values from another custom object?

    ReplyDelete
  14. hi,
    here i need one thing that
    if the header checkbox is selected, it selects all values but if i uncheck one value the header value must be unchecked.
    in this case it is not working.
    for that i need script code

    ReplyDelete
  15. Hi,
    I was looking to use this as a way to show all of the available demoable products in demo requests rather then have the user iterate through 10 - 12 times with all of the products needed to be demo'd.
    So the user creates the demo (D0001) and clicks 'new' to view a page with the 25 products. they check the box for those required and then the class inserts a line per demoObject.

    So I am looking at this and taking it apart but am getting an error
    "
    Save error: Unable to perform save on all files: com.salesforce.ide.api.metadata.types.Metadata$JaxbAccessorF_fullName cannot be cast to com.sun.xml.internal.bind.v2.runtime.reflect.Accessor massAddDemoProducts.cls
    "
    which seems to be a hangover from teh code but I do not have fullName in the class anywhere... Any ideas?

    ReplyDelete
  16. Hi ,
    Thank you for the post. This is really helpful.Could you please help me do the partial page refresh with this page.I am able to delete partial page refresh is not happening.
    thank,
    -Rajesh.

    ReplyDelete
  17. Hi,
    Thanks for your post. If I would like to bring the search page instead of detail page and will have button as "detail/back" to redirect to detail page of campaign then what would be the approach?. I meant I don't want to pop up a windows for this search.

    Thanks,
    Preya

    ReplyDelete