function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Andrei KuznetsovAndrei Kuznetsov 

Updating Contacts associated with Account

Hello! I'm new to salesforce and just received my first sophisticated task. Our org is quite plane and I can't find any good examples of Visualforce pages and apex code. Here is my task and if anyone has done something similar, please advice me how to approach it.

 

On Account standard screen I need to place button, let's call it 'Use Account Address'. Clicking on this button should open up VF page that list all the Contacts for this Account. Beside each Contact record there should be check box. There should be also 'Update Selected' button on this page, clicking on which will update all selected Contacts with Account's address and return user back to Account page.

 

Thanks a lot in advance!

Best Answer chosen by Andrei Kuznetsov
rmehrmeh

Hi,

 

First of all, i was also in doubt whether select 'selectedContacts' contains value, thats why i asked you.

However i dont know why the getContacts() is being called twice.

Are you using rerender attribute twice? This is the only possibilty i can think of.

Apart from that in the getSelectedFunction iterate "lstFinalContactWrapper" list instead of  "contactList" list and check after putting debug values check whether you get values in selectedContacts.

 

The value should come here as you are using the above list while you are updating the records.

 

Let me know after making changes, it works or not.

 

All Answers

rmehrmeh

Hi,

 

Can you just post the code of whatever you have done uptil now

This will help us understand better what problem you are facing.
Andrei KuznetsovAndrei Kuznetsov

Yes, of course. I placed button on Account layout 'Use Account Address'. Clicking on it calls the following Visual Force page.

 

========================================================================================

<apex:page standardController="Account"  extensions="Update_ContactsAddress"  tabStyle="Contact" label="Contacts">
    <apex:sectionHeader title="Contacts for {!account.name}"/>
    <apex:form >
    <apex:pageMessages />
    <apex:pageblock id="thePage">           
        <apex:pageBlockButtons id="buttonsBottom" location="bottom">
            <apex:commandButton id="checkBottom" value="UpdateSelected" title="Update Selected" onclick="updateContacts"; return false;" />
            <apex:commandButton id="cancelBottom" value="Cancel" onclick="navigateToUrl('{!BLANKVALUE($CurrentPage.parameters.retURL,'/home/home.jsp')}'); return false;" />
        </apex:pageBlockButtons>
        <apex:pageblocktable value="{!account.contacts}" var="AC" id="contactsForAccount">
            <apex:column>
                <apex:inputCheckbox />
            </apex:column>
            <apex:column headerValue="Contact Name" value="{!AC.Name}" />
            <apex:column headerValue="Title" value="{!AC.Title}" />
            <apex:column headerValue="Email" value="{!AC.Email}" />
            <apex:column headerValue="Phone" value="{!AC.Phone}" />
            <apex:column headerValue="Employed By" value="{!AC.Employed_By__c}" />
        </apex:pageblocktable>
    </apex:pageblock>
    </apex:form>
</apex:page>

========================================================================================

 

I've created "Update_ContactsAddress" apex class, which is just a shell now. What I need to do next is somehow to pass selected Contacts (where inputCheckbox value is true) to this class/method and update those Contacts with Company's address.

 

Please let me know if you need more info.

 

Thanks a lot.

 

rmehrmeh

Hi,

 

I would suggest you to make use of inner class and return the list of the inner class.

This inner class will take care of the checkbox by writing an overriding constructor

 

So if your inner class is say Test2

// Declarations

public Contact theCon {get; set;}
public Boolean selected{get; set;}

public class Test2(Contact con, Boolean s)

{

      theCon = p; 
      selected = s;

}  

 

So instead of

<apex:pageblocktable value="{!write a method which is returning a list of inner class}" var="AC" id="contactsForAccount">

   <apex:column>
               <apex:inputCheckbox id="chkChild" value="{!AC.selected}" onclick="chechUncheckHeader(this)">

               </apex:inputCheckbox>   

               <script>                                                                  
                           arrCheckbox.push(document.getElementById('{!$Component.chkChild}'));  // declare an ARRAY in javascript                      
               </script>    
    </apex:column>

 

// outside pageBlockTable write the javascript function which is called onclick

 

 function chechUncheckHeaderForCIC(obj)

{               
       if(!obj.checked)
        {
               // declare objHeaderCheckbox  on top of your page as a string variable something like var objHeaderCheckbox  = '';

                if(objHeaderCheckbox  != null && objHeaderCheckbox != '')
                document.getElementById(objHeaderCheckbox).checked = false;
       }            

}

 

Can you tell me how are you getting the contacts related to the accounts. Is it through the visual Force page or javascript URL?

 

Please let me know if it is still not clear to you.

 

 

Andrei KuznetsovAndrei Kuznetsov

I'm using this to get the list of contacts associated with the account. This statement completely handled by platform.

 

<apex:pageblocktable value="{!account.contacts}" var="c" id="table">

 

I also did more researh and found out that Select All, Select None, and Sorting can be all done in the class. For now, I built page that makes calls to functions that I don't have yet (just have methods and properties declarations), sort of sceleton, so my page looks like this now:

 

===========================================================================================

<apex:page standardController="Account" extensions="TD_ContactsAddressController" tabstyle="Contact" id="thePage" title="Update {!Account.Name} {!$ObjectType.contact.label} Addresses">
    <apex:sectionHeader title="Update Contact Addresses"/>
            <apex:panelgrid width="40%" columns="2" frame="none" border="0">
            <apex:outputtext value="{!$ObjectType.account.label} Name:" />
            <apex:outputLink value="{!URLFOR($Action.Account.View,Account.Id)}"
                target="_blank">{!Account.Name}</apex:outputLink>
            <apex:outputtext >
                <b>Address Information:</b>
            </apex:outputtext>
            <apex:outputtext>
                {!Account.billingstreet}&nbsp;<br/>{!Account.billingcity},&nbsp;{!Account.billingstate}<br/>{!Account.billingcountry},&nbsp;{!Account.billingpostalcode}
            </apex:outputtext>
        </apex:panelgrid>
   
    <apex:form id="multiContactForm">
    <apex:pageMessages />
    <apex:pageblock id="thePage">
               
        <apex:pageBlockButtons id="buttonsBottom" location="bottom">
            <apex:commandButton id="checkBottom" value="UpdateSelected" title="Update Selected" onclick="doCheck(); return false;" />
            <apex:commandButton id="cancelBottom" value="Cancel" action="{!cancel}" id="Cancel"/>
        </apex:pageBlockButtons>       

        <apex:pageblocktable value="{!account.contacts}" var="c" id="table">
           
            <apex:column >
                <apex:facet name="header">
                    <apex:actionregion>
                        <apex:outputPanel rendered="true">
                            <apex:commandlink value="All" rerender="PageBlock"
                                action="{!selectAll}" status="selectstatus" />
                                <apex:outputtext value=" | " />
                                <apex:commandlink value="None" rerender="PageBlock"
                             action="{!selectNone}" status="selectstatus" />
                        </apex:outputPanel>
                    </apex:actionregion>
                </apex:facet>
                <apex:inputCheckbox value="{!selected}"/>
            </apex:column>
           
            <apex:column >
                    <apex:facet name="header">
                        <apex:outputpanel >
                            <apex:commandLink value="{!$ObjectType.contact.fields.name.label}{!IF(sortExp=='name',IF(sortDirection='ASC','▼','▲'),'')}"
                                rerender="table" action="{!resetUContact}" rendered="true">
                                <apex:param value="name" name="column"
                                    assignTo="{!sortExp}"></apex:param>
                            </apex:commandLink>
                            <apex:outputtext value="{!$ObjectType.contact.fields.name.label}"
                                rendered="true"></apex:outputtext>
                        </apex:outputpanel>
                    </apex:facet>
                    {!c.Name}
            </apex:column>          

            <apex:column headerValue="Title" value="{!c.Title}" />
            <apex:column headerValue="Email" value="{!c.Email}" />
            <apex:column headerValue="Phone" value="{!c.Phone}" />
            <apex:column headerValue="Employed By" value="{!c.Employed_By__c}" />
        </apex:pageblocktable>
    </apex:pageblock>
    </apex:form>
</apex:page>

===========================================================================================

 

At this point it looks like all work has to be done in the class, as Visualforce doesn't really handle sorting and doesn't have built in 'Select All' and 'Select None' functionality. I will try what you suggested and will post the results.

 

Thank you!

rmehrmeh

Hi,

 

What you said is absolutely right.

You cannot handle Select All, Select None functionality directly in VisualForce.

This was the reason i suggested that instead of using value="{!account.contacts}" in pageblockTable use the List of the inner class.

 

Please let me know if further help needed.

Andrei KuznetsovAndrei Kuznetsov

Hi,

 

I will focus on writing the class today to get the list of contacts and manipulate it. For now, I can't compile suggested VF page. The error is "Error: The entity name must immediately follow the '&' in teh entity reference. at line 44"

 

Here is the page:

============================================================================================

<apex:page standardController="Account" extensions="TD_ContactsAddressController" tabstyle="Contact" id="thePage" title="Update {!Account.Name} {!$ObjectType.contact.label} Addresses">
    var objHeaderCheckbox  = ""
    <apex:sectionHeader title="Update Contact Addresses"/>
            <apex:panelgrid width="40%" columns="2" frame="none" border="0">
            <apex:outputtext value="{!$ObjectType.account.label} Name:" />
            <apex:outputLink value="{!URLFOR($Action.Account.View,Account.Id)}"
                target="_blank">{!Account.Name}</apex:outputLink>
            <apex:outputtext >
                <b>Address Information:</b>
            </apex:outputtext>
            <apex:outputtext >
                {!Account.billingstreet}&nbsp;<br/>{!Account.billingcity},&nbsp;{!Account.billingstate}<br/>{!Account.billingcountry},&nbsp;{!Account.billingpostalcode}
            </apex:outputtext>
        </apex:panelgrid>
   
    <apex:form id="multiContactForm">
    <apex:pageMessages />
    <apex:pageblock id="thePage">               
        <apex:pageBlockButtons id="buttonsBottom" location="bottom">
            <apex:commandButton id="checkBottom" value="UpdateSelected" title="Update Selected" onclick="doCheck(); return false;" />
            <apex:commandButton id="cancelBottom" value="Cancel" action="{!cancel}" id="Cancel"/>
        </apex:pageBlockButtons>       

        <apex:pageblocktable value="{!account.contacts}" var="AC" id="contactsForAccount">
           <apex:column>
               <apex:inputCheckbox id="chkChild" value="{!AC.selected}" onclick="chechUncheckHeader(this)">
               </apex:inputCheckbox>
               <script>                                                                 
                   arrCheckbox.push(document.getElementById('{!$Component.chkChild}'));  // declare an ARRAY in javascript                      
               </script>    
            </apex:column>
          
            <apex:column headerValue="Contact Name" value="{!c.Name}" />
            <apex:column headerValue="Title" value="{!c.Title}" />
            <apex:column headerValue="Email" value="{!c.Email}" />
            <apex:column headerValue="Phone" value="{!c.Phone}" />
            <apex:column headerValue="Employed By" value="{!c.Employed_By__c}" />
        </apex:pageblocktable>
    </apex:pageblock>
   
     function chechUncheckHeaderForCIC(obj)
     {              
         if(!obj.checked)
         {
            if(objHeaderCheckbox  != null && objHeaderCheckbox != '')
            document.getElementById(objHeaderCheckbox).checked = false;
         }
     }   
    </apex:form>
</apex:page>

============================================================================================

 

Please have a look. Thank you.

rmehrmeh

Hi,

 

After looking at the VisualForce Page, i can locate some minor mistakes which may be a reason for your error.

  • On the 2nd line, there is a javascript declaration. Please make a note that javascript code should always be embedded in between start and end of <script> </script> tags. Also every javascript statement should end with a semicolon.
  • Apart from the above changes, please also declare the variable of Array Type right below the 2nd line as var arrCheckbox = new Array();
  • In the PageBlockTable declarartion if var="AC" then why other values in <apex:column> declaration has been shown as value="{!c.}" 
  • Again after the end of </apex:pageblock>, a javascript function is being called without start and end of <script> tags.
  • Last, the function call name in javascript is chechUncheckHeader and not chechUncheckHeaderForCIC. I think that was a mistake from myside i mentioned it incorrectly in my previous posts.

Please do make the changes and try compiling your code.

Andrei KuznetsovAndrei Kuznetsov

This was quite a fight. Anyways, got 2 working solutions after all and decided to stick with one. Here what I got so far. It seems working, but the real test comes when I actually have to modify selected Contacts, based on the fact it was selected by checkbox or not. My second challenge is to add ascending and decending sorting to 'Name' field (link). If you are still interesting in going to the end =) I would really appreciate your input.

 

Class:

============================================================================================

public class TD_ContactsAddressController
{
    List<contactwrapper> contactList = new List<contactwrapper>();
    List<Contact> selectedContacts = new List<Contact>();
   
    //Constructor
    public TD_ContactsAddressController(ApexPages.StandardController controller){

    }
       
    public List<contactwrapper> getContacts()
    {
        for(Contact c : [Select Name, Title, Email, Phone, Employed_By__c from Contact where AccountId = :Apexpages.Currentpage().getparameters().get('Id')])
        contactList.add(new contactwrapper(c));
        return contactList;
    }
   
    public PageReference getSelected()
    {
        selectedContacts.clear();
        for(contactwrapper conwrapper : contactList)
        if(conwrapper.selected == true)
        selectedContacts.add(conwrapper.con);
        return null;
    }
   
    public List<Contact> GetSelectedContacts()
    {
        if(selectedContacts.size()>0)
        return selectedContacts;
        else
        return null;
    }   
   
    public class contactwrapper
    {
        public Contact con{get; set;}
        public Boolean selected {get; set;}
        public contactwrapper(Contact c)
        {
            con = c;
           selected  =  false;
        }
    }
}

========================================================================================

 

Page:

========================================================================================

<apex:page standardController="Account" extensions="TD_ContactsAddressController" tabstyle="Contact" id="thePage" title="Update {!Account.Name} {!$ObjectType.contact.label} Addresses">
    <script>var objHeaderCheckbox  = ""</script>
    <apex:sectionHeader title="Update Contact Addresses"/>
            <apex:panelgrid width="40%" columns="2" frame="none" border="0">
            <apex:outputtext value="{!$ObjectType.account.label} Name:" />
            <apex:outputLink value="{!URLFOR($Action.Account.View,Account.Id)}"
                target="_blank">{!Account.Name}</apex:outputLink>
            <apex:outputtext >
                <b>Address Information:</b>
            </apex:outputtext>
            <apex:outputtext >
                {!Account.billingstreet}&nbsp;<br/>{!Account.billingcity},&nbsp;{!Account.billingstate}<br/>{!Account.billingcountry},&nbsp;{!Account.billingpostalcode}
            </apex:outputtext>
        </apex:panelgrid>
   
    <apex:form id="multiContactForm">
    <apex:pageMessages />
    <apex:pageblock id="thePage">               
        <apex:pageBlockButtons id="buttonsBottom" location="bottom">
            <apex:commandButton id="checkBottom" value="UpdateSelected" title="Update Selected" onclick="doCheck(); return false;" />
            <apex:commandButton id="cancelBottom" value="Cancel" action="{!cancel}" id="Cancel"/>
        </apex:pageBlockButtons>
              
        <apex:pageblocktable value="{!contacts}" var="c" id="contactsForAccount">
            <apex:column >
            <apex:facet name="header"> <apex:inputCheckbox >
            <apex:actionSupport event="onclick" action="{!GetSelected}" onsubmit="checkAll(this)" rerender="Selected_PBS"/>
            </apex:inputCheckbox></apex:facet>
            <apex:inputCheckbox value="{!c.selected}" id="checkedone">
            <apex:actionSupport event="onclick" action="{!GetSelected}" rerender="Selected_PBS"/>
            </apex:inputCheckbox></apex:column>
            <apex:column headerValue="Contact Name">
                <apex:commandLink value="{!c.con.Name}" onclick="navigateToUrl('/{!c.con.Id}'); return false;" />
            </apex:column>               
            <apex:column headerValue="Title" value="{!c.con.Title}" />
            <apex:column headerValue="Email" value="{!c.con.Email}" />
            <apex:column headerValue="Phone" value="{!c.con.Phone}" />
            <apex:column headerValue="Employed By" value="{!c.con.Employed_By__c}" />
        </apex:pageblocktable>
    </apex:pageblock>
    <script>
    function checkAll(cb)
    {
    var inputElem = document.getElementsByTagName("input");
    for(var i=0; i<inputElem.length; i++)
    {
    if(inputElem[i].id.indexOf("checkedone")!=-1)
    inputElem[i].checked = cb.checked;
    }
    }   
    </script> 
    </apex:form>
</apex:page>   

========================================================================================

 

Thank  you!

rmehrmeh

Hi,

 

The class looks good. But are you able to get through the select checkbox and select all checkbox functionality?

For sorting of your Contact Name, you need to first of all create a class and copy the code as mentioned in the below link.

 

http://wiki.developerforce.com/index.php/Sorting_Tables.

 

As you can read the code from the above link, the List getting passed is of SObject Type.

So, in your public List<contactwrapper> getContacts() method,

  • First declare a List<Contact> globally like List<Contact>= new List<Contact>();
  • In your method where you are iterating your Contact and adding it to the Inner class List also add it to your contact List.
  • In your apex code as mentioned in the link above, pass your contact list as below:

 

 public void doSort(){
String order = 'asc';
/*This checks to see if the same header was click two times in a row, if so it switches the order.*/
if(previousSortField == sortField){
order = 'desc';
previousSortField = null;
}else{
previousSortField = sortField;
}
//To sort the table we simply need to use this one line, nice! superSort.sortList(sortContacts,sortField,order);
}

 And finally in your page do the following changes:

 

 

<apex:column headerValue="Name" >
<apex:facet name="header">
<apex:commandLink value="Name" action="{!doSort}" rerender="contactsForAccount">
<apex:param name="sortField" value="Name" assignTo="{!sortField}"/>
</apex:commandLink>
</apex:facet>
<apex:outputLabel value="{!c.con.Name}" rendered="true"/>
</apex:column>

 This will solve your sorting functionality.

 

 

Andrei KuznetsovAndrei Kuznetsov

Yes, I added another page block that will only display selected Contacts, contained in selectedContacts list. I guess I can use this list further to update Contact Address. I will try your solution for sorting and will let you know.

 

Thank you,

Andrei KuznetsovAndrei Kuznetsov

Interesting....

 

I added global variable

 

==========================================================

public class TD_ContactsAddressController
{
    List<contactwrapper> contactList = new List<contactwrapper>();
    List<Contact> selectedContacts = new List<Contact>();
    // Sorting
    List<Contact> sortContacts = new List<Contact>();

========================================================

 

And in getContacts I added code to populate this new list. But salesforce complaining if I do this like this. I can only populate either selected contactList on sortContact list. Or I have to execute SQL statement again. Is it how salesforce work or I'm missing something? Thanks!

 

==========================================================

        
    public List<contactwrapper> getContacts()
    {
        for(Contact c : [SELECT Name, Title, Email, Phone, Employed_By__c from Contact where AccountId = :Apexpages.Currentpage().getparameters().get('Id') ORDER BY Name ASC])
        contactList.add(new contactwrapper(c));

      

        // Had to run query again.
        for(Contact c : [SELECT Name, Title, Email, Phone, Employed_By__c from Contact where AccountId = :Apexpages.Currentpage().getparameters().get('Id') ORDER BY Name ASC])
        sortContacts.add(c);
        return contactList;
    }

================================================================================

rmehrmeh

Hi,

 

I dont understand what is the error you are getting. Because i tried the same thing in my org it is working fine.

Can you tell me what error you are getting.

I am also posting my code for your reference so that you can figure it out if any mistakes.

 

 

public List<Test2> getcontactsValue()
	{
	     for(Contact contact:[Select Name, Id,AccountId From Contact c where AccountId =: Apexpages.Currentpage().getparameters().get('Id')])
	     {
		lstContactTest.add(contact);
		System.debug('lstContactTest=============' +lstContactTest);
		Test2 objTest2 = new Test2(contact, false);
		lstTest2.add(objTest2);
	      }
	      if(lstTest2 != null && !lstTest2.isEmpty())
	       {
			return lstTest2;
		}
		else
		{
			return null;
		}
	}

Please do let me know what error you are receiving if after making alterations also, you are getting the same error.

 

 

Andrei KuznetsovAndrei Kuznetsov

Hi,

 

1. I added curly brackets and was able to compile my class. So, it was just syntax error.

2. I gave it a try and getting strange results. First of all, if I'm using 'Contact Name' column definition in page as per your example, I'm loosing the link that is clicking on Contact's name should take me to this Contact record. Trying to add it like this:

<apex:commandLink value="Name" action="{!doSort}" rerender="contactsForAccount" onclick="navigateToUrl('/{!c.con.Id}'); return false;" >

 

produces funny results. That is Salesforce asking me to login again each time I click on 'Name' column header to resort Contacts. If I remove onclick attribute and have it exactly as in your example then every attempt to sort will just duplicate number of Contacts:

Here what I have:

1. My SortClass is a copy of the one from this link, with no changes:

http://wiki.developerforce.com/index.php/Sorting_Tables

 

2. My Class now looks like this:

==========================================================================================

public class TD_ContactsAddressController
{
    List<contactwrapper> contactList = new List<contactwrapper>();
    List<Contact> selectedContacts = new List<Contact>();
    // Sorting
    List<Contact> sortContacts = new List<Contact>();
    public String sortField {get; set;}
    public String previousSortField {get; set;}
   
    //Constructor
    public TD_ContactsAddressController(ApexPages.StandardController controller){
 
    }
       
    public List<contactwrapper> getContacts()
    {
        for(Contact c : [SELECT Name, Title, Email, Phone, Employed_By__c from Contact where AccountId = :Apexpages.Currentpage().getparameters().get('Id') ORDER BY Name ASC])
        {           
            sortContacts.add(c);
            System.debug('sortContacts: ' + sortContacts);
            contactList.add(new contactwrapper(c)); 
            System.debug('contactList: ' + contactList);         
        }
       
        //if (contactList != null && !contactList.IsEmpty())
        //{    return contactList;     }
        //{    return null;            }
        return contactList;

    }
   
    public PageReference getSelected()
    {
        selectedContacts.clear();
        for(contactwrapper conwrapper : contactList)
        if(conwrapper.selected == true)
        selectedContacts.add(conwrapper.con);
        return null;
    }
   
    public List<Contact> GetSelectedContacts()
    {
        if(selectedContacts.size()>0)
        return selectedContacts;
        else
        return null;
    }   
   
    public class contactwrapper
    {
        public Contact con{get; set;}
        public Boolean selected {get; set;}
        public contactwrapper(Contact c)
        {
            con = c;
           ;
        }
    }
   
    //Sorting.
    public void doSort(){
        String order = 'asc';
       
        /*This checks to see if the same header was click two times in a row, if so it switches the order.*/
        if(previousSortField == sortField){
            order = 'desc';
            previousSortField = null;
        }else{
            previousSortField = sortField;
        }
      
        //To sort the table we simply need to use this one line, nice!
        superSort.sortList(sortContacts, sortField, order);
    }   
 }

==========================================================================================

 

3. Page (I removed link to the Contact record, but must have it after all):

==========================================================================================

<apex:page standardController="Account" extensions="TD_ContactsAddressController" tabstyle="Contact" id="thePage" title="Update {!Account.Name} {!$ObjectType.contact.label} Addresses">
    <script>var objHeaderCheckbox  = ""</script>
    <apex:sectionHeader title="Update Contact Addresses"/>
            <apex:panelgrid width="40%" columns="2" frame="none" border="0">
            <apex:outputtext value="{!$ObjectType.account.label} Name:" />
            <apex:outputLink value="{!URLFOR($Action.Account.View,Account.Id)}"
                target="_blank">{!Account.Name}</apex:outputLink>
            <apex:outputtext >
                <b>Address Information:</b>
            </apex:outputtext>
            <apex:outputtext >
                {!Account.billingstreet}&nbsp;<br/>{!Account.billingcity},&nbsp;{!Account.billingstate}<br/>{!Account.billingcountry},&nbsp;{!Account.billingpostalcode}
            </apex:outputtext>
        </apex:panelgrid>
   
    <apex:form id="multiContactForm">
    <apex:pageMessages />
    <apex:pageblock id="thePage">               
        <apex:pageBlockButtons id="buttonsBottom" location="bottom">
            <apex:commandButton id="checkBottom" value="UpdateSelected" title="Update Selected" onclick="doCheck(); return false;" />
            <apex:commandButton id="cancelBottom" value="Cancel" action="{!cancel}" id="Cancel"/>
        </apex:pageBlockButtons>
              
        <apex:pageblocktable value="{!contacts}" var="c" id="contactsForAccount">
            <apex:column >
            <apex:facet name="header"> <apex:inputCheckbox >
            <apex:actionSupport event="onclick" action="{!GetSelected}" onsubmit="checkAll(this)" rerender="Selected_PBS"/>
            </apex:inputCheckbox></apex:facet>
            <apex:inputCheckbox value="{!c.selected}" id="checkedone">
            <apex:actionSupport event="onclick" action="{!GetSelected}" rerender="Selected_PBS"/>
            </apex:inputCheckbox></apex:column>
            <apex:column headerValue="Contact Name">
            <apex:facet name="header">
                <apex:commandLink value="Name" action="{!doSort}" rerender="contactsForAccount" >
                <apex:param name="sortField" value="Name" assignTo="{!sortField}"/>
                </apex:commandLink>
                </apex:facet>
                <apex:outputLabel value="{!c.con.Name}" rendered="true"/>
            </apex:column>               
            <apex:column headerValue="Title" value="{!c.con.Title}" />
            <apex:column headerValue="Email" value="{!c.con.Email}" />
            <apex:column headerValue="Phone" value="{!c.con.Phone}" />
            <apex:column headerValue="Employed By" value="{!c.con.Employed_By__c}" />
        </apex:pageblocktable>   
    </apex:pageblock>
    <script>
    function checkAll(cb)
    {
        var inputElem = document.getElementsByTagName("input");
        for(var i=0; i<inputElem.length; i++)
        {
            if(inputElem[i].id.indexOf("checkedone")!=-1)
            inputElem[i].checked = cb.checked;
        }
    }   
    </script> 
    </apex:form>
</apex:page>

==========================================================================================

 

Thank you!

rmehrmeh

Hi,

 

I missed telling you on that part.

Please do the following changes to your code.

 

========================== VisualForce Page================================

<apex:column headerValue="Contact Name">
           <apex:facet name="header">
                <apex:commandLink value="Name" action="{!doSort}" rerender="contactsForAccount" >
                           <apex:param name="sortField" value="Name" assignTo="{!sortField}"/>
                </apex:commandLink>
            </apex:facet>
            <apex:outputLink value="{!c.ContactURL}">{!c.con.Name}</apex:outputLink>

</apex:column>

==========================Apex Controller===================================    

 

  public class contactwrapper
    {
        public Contact con{get; set;}
        public Boolean selected {get; set;}

        public String ContactURL{get;set;}
        public contactwrapper(Contact c)
        {
            con = c;
            ContactURL = '/' + c.Id;
        }
    }

Andrei KuznetsovAndrei Kuznetsov

Thanks for the fix of the link. I also fixed duplicated records problem by adding line in red to the code. So now, trying to sort will do nothing, but will clear already selected records. The rest I've done and contact update is working. Plus I changed the page to make it more UI appealing and added refreshing of the page after Contact update is done. The only little problem I have is that if Check All box was checked, it doesn't clear it

 

-------------------------------------------------------------------------------------------------------------------------------------------------------

    public List<contactwrapper> getContacts()
    {
        contactList.clear();
        for(Contact c : [SELECT Name, Title, Email, Phone, Employed_By__c, TD_Use_Account_Address__c from Contact where AccountId = :Apexpages.Currentpage().getparameters().get('Id') ORDER BY Name ASC])
        {           
            sortContacts.add(c);
            System.debug('sortContacts: ' + sortContacts);
            contactList.add(new contactwrapper(c)); 
            System.debug('contactList: ' + contactList);         
        } 
        return contactList;
    }

-------------------------------------------------------------------------------------------------------------------------------------------------------

So, do you think we can make the sorting work?! =) Thanks for all your help.

rmehrmeh

Hi,

 

Here is the code which will take care of the check All Box to clear.

 

<apex:column headerValue="" id="clchkBox" rendered="true" width="5%">    
<apex:facet name="header">
<apex:inputCheckbox id="chkHeader" onclick="checkUncheckFor(this, '{!$Component.chkHeader}')">                              </apex:inputCheckbox>                        
</apex:facet>           
<apex:inputCheckbox id="chkChild" value="{!c.selected}" onclick="chechUncheckHeader(this, '{!$Component.chkHeader}')"></apex:inputCheckbox>                                                    <script>                                                                        arrCheckbox.push(document.getElementById('{!$Component.chkChild}'));     
</script> </apex:column>

You need to define an array right at the top of your page where you have declared

<script>

   var objHeaderCheckbox  = ''; // please do this change

    var arrCheckbox = new Array();

</script>

 

Once you have declared your array, reintialize it just below your pageBlock

<apex:pageblock id="thePage">  

<script>                    
        arrCheckbox = new Array();     

        var isAllChecked = false;                       

</script>

 

Finally at the end tag of your pageBlock put the following code:

<script>
      if(arrCheckbox != null && arrCheckbox.length > 0)
       {
                 for(var i = 0; i < arrCheckbox.length; i++)
                  {
                         if(arrCheckbox[i].checked)
                         {
                              isAllChecked = true;
                         }
                         else
                         {
                             isAllChecked = false;
                             break;
                          }
                    }
               }
               if(objHeaderCheckbox != '')
               {
                      document.getElementById(objHeaderCheckbox).checked = isAllChecked;
               }
               function checkUncheck(obj, comp)
               {
                     objHeaderCheckbox = comp;
                     if(obj.checked)
                     {
                          if(arrCheckbox != null && arrCheckbox.length > 0)
                          {
                                 for(var i = 0; i < arrCheckboxForCIC.length; i++)
                                 {
                                       arrCheckboxForCIC[i].checked = true;
                                 }
                         }
                   }
                   else
                   {
                         if(arrCheckbox != null && arrCheckbox.length > 0)
                         {
                               for(var i = 0; i < arrCheckbox.length; i++)
                               {
                                     arrCheckbox[i].checked = false;
                               }
                         }
                    }
          }                               
          function chechUncheckHeader(obj, headerComp)
          {                                
                                        if(!obj.checked)
                                        {
                                                if(objHeaderCheckbox != null && objHeaderCheckbox != '')
                                                    document.getElementById(objHeaderCheckbox).checked = false;
                                        }                             
                                        
                                    }
  </script>

 

This should solve your Check all functionality.

Let me know if you are facing any other problem in Check all functionality.

 

 

rmehrmeh

For the sorting functionality lets take it step by step:

 

  • Put  rerender=" thePage" in the following line <apex:commandLink value="Name" action="{!doSort}" rerender="thePage">

The above are the changes in VF page.

 

Now the changes in Apex Controller:

 

  • Now instead of running the query in your getContacts() method, call a method right up in your constructor:

//Constructor
    public TD_ContactsAddressController(ApexPages.StandardController controller){
        chkValuesContact();
    }

 

  • Shift your query in the above function

public PageReference chkValuesContact()

{

     for(Contact c : [SELECT Name, Title, Email, Phone, Employed_By__c from Contact where AccountId = :Apexpages.Currentpage().getparameters().get('Id') ORDER BY Name ASC])
        {           
            sortContacts.add(c);
            System.debug('sortContacts: ' + sortContacts);
            contactList.add(new contactwrapper(c)); 
            System.debug('contactList: ' + contactList);         
        }

     return null;

}

 

  • Now finally in your getContacts() method do the following changes
  • Declare a List<contactwrapper> lstFinalContactWrapper = new List<contactwrapper>(); //globally

and then do as follows:


public List<contactwrapper> getContacts()
    {
        lstFinalContactWrapper= new List<contactwrapper>();
        if(!
sortContacts.isEmpty()){
            for(Contact objCon:
sortContacts){
                contactwrapper objFinalContact = new contactwrapper(objCon, false);
                lstFinalContactWrapper.add(objFinalContact);
            }
        }
        if(!lstFinalContactWrapper.isEmpty())
        {
            return lstFinalContactWrapper;
        }
        else{return null;}
    }

 

This will definitely work the sorting functionality.

Please let me know if you are stuck up anywhere.

Andrei KuznetsovAndrei Kuznetsov

Thank you. I will try it shortly. I only have couple of days to move it to UAT and must finish unit testing for my class. My company's requirement is 100% of coverage for the classes. Then I will have time to finish sorting. I'm looking for any info on how pages are tested. Especially in my case, when I have somehow to mimic user's input (checked records) to the test method. If you could help with this, it would be great, as I don't see any solid material on this. Here is what I have so far (and you already have the class):

=======================================================================================

@isTest
private class TD_TST_ContactsAddressController {

    static testMethod void testTD_ContactsAddressController() {       
       
        System.debug('Inserting test Account with associated Contacts');
       
        Account account1 = new Account (Billingstreet='Company Address', Billingcity='Company City',
          Billingstate='Company State', Billingcountry='Company Country', Billingpostalcode='COMZIP');
        insert account1; 
       
        List<Contact> contacts1 = new List<Contact>();
        for(integer i=0; i<25; i++){
            contacts1.add(new Contact(AccountId=account1.Id, TD_Use_Account_Address__c = false));    
        }
        insert contacts1;
       
        for(Contact c : contacts1){
            System.assertNotEquals(c.Id,null);
        }       
       
        Test.StartTest();
        TD_ContactsAddressController testController = new TD_ContactsAddressController(new ApexPages.StandardController(account1));
    }     
}

=======================================================================================

 

Thank you!

 

Andrei KuznetsovAndrei Kuznetsov

Never mind unit testing. I got it done with 100% coverage. Wasn't that difficult actually. If you want, I can post it. I'm looking into your suggestions about sorting.

Thanks again.

Andrei KuznetsovAndrei Kuznetsov

I did all the changes exactly as you asked first and got an error when trying to save controller.

 

<< Error:  Compile Error: Constructor not defined: [TD_ContactsAddressController.contactwrapper].<Constructor>(SOBJECT:Contact,Boolean) at line 22 column 50. >>

 

This is the failing line in getContacts():

                contactwrapper objFinalContact = new contactwrapper(objCon, false);

 

If I change it like this, it compiles, and sorting works, but sorting will earase all selections, which is not acceptable. But, it's getting close.

 

Thanks,

rmehrmeh

Are you able to solve the error which you mentioned below on the line 22 column 50.

The only error i can see here is your constructor is defined without those arguments i am passing.

 

Apart from that sorting will erase the selections because we are putting the second parameter as false in the constructor.

 

say: contactwrapper objFinalContact = new contactwrapper(objCon, false);

The false is removing the selections.

 

Please post your whole code, so i can have a look at it.

 

 

Andrei KuznetsovAndrei Kuznetsov

Hi,

Select All and clearing up check box after update are not working. The only one thing that is working is sorting, with one small glitch, that is records comes up sorted by Contact Name in asc order and first attempt to resort records first time also sorts it asc instead of desc. Here is what I got so far, hope I didn't miss any of your recommendations:

 

Page:

**********************************************************************************************************************

<apex:page standardController="Account" extensions="TD_ContactsAddressController" tabstyle="Contact" id="thePage" title="Update {!Account.Name} {!$ObjectType.contact.label} Addresses">
    <script>
    var objHeaderCheckbox  = "";
    var arrCheckbox = new Array();
    </script>
   
    <apex:sectionHeader title="Update Contact Addresses"/>
        <apex:panelgrid width="40%" columns="2" frame="none" border="0">
            <apex:outputtext value="{!$ObjectType.account.label} Name:" />
            <apex:outputLink value="{!URLFOR($Action.Account.View,Account.Id)}"
                target="_blank">{!Account.Name}</apex:outputLink>
            <apex:outputtext >
                <b>Address Information:</b>
            </apex:outputtext>
            <apex:outputtext >
                {!Account.billingstreet},<br/>{!Account.billingcity},&nbsp;{!Account.billingstate}<br/>{!Account.billingcountry},&nbsp;{!Account.billingpostalcode}
            </apex:outputtext>
        </apex:panelgrid>
   
    <apex:form id="multiContactForm">
        <apex:pageMessages />
       
        <apex:pageblock id="thePage">
            <script>                    
                arrCheckbox = new Array();
                var isAllChecked = false;
            </script>
               
            <apex:actionFunction name="doUpdate" action="{!doUpdateAddress}" reRender="contactsListPanel" status="updateStatus" />
           
            <apex:pageBlockButtons id="buttonsBottom" location="both">
                <apex:commandButton id="checkBottom" value="UpdateSelected" title="Update Selected" onclick="doUpdate(); return false;" />
                <apex:commandButton id="cancelBottom" value="Cancel" action="{!cancel}"/>
            </apex:pageBlockButtons>
              
        <apex:outputPanel id="contactsListPanel">
            <apex:message />
            <apex:actionStatus id="updateStatus" startStyle="{font-weight:bold;}" startText="Updating...">
              <apex:facet name="stop">
                <apex:pageblocktable value="{!contacts}" var="c" id="contactsForAccount">
                   
                    <apex:column headerValue="" id="clchkBox" rendered="true" width="5%">   
                    <apex:facet name="header">
                    <apex:inputCheckbox id="chkHeader" onclick="checkUncheckFor(this, '{!$Component.chkHeader}')">                             
                    </apex:inputCheckbox>                       
                    </apex:facet>          
                    <apex:inputCheckbox id="chkChild" value="{!c.selected}" onclick="chechUncheckHeader(this, '{!$Component.chkHeader}')">
                    </apex:inputCheckbox>
                        <script>
                            arrCheckbox.push(document.getElementById('{!$Component.chkChild}'));
                        </script>
                    </apex:column>
                                    
                    <apex:column /><apex:column headerValue="Contact Name">
                        <apex:facet name="header">
                        <apex:commandLink value="Contact Name" action="{!doSort}" rerender="thePage" >
                           <apex:param name="sortField" value="Name" assignTo="{!sortField}"/>
                        </apex:commandLink>
                        </apex:facet>
                        <apex:outputLink value="{!c.ContactURL}">{!c.con.Name}</apex:outputLink>
                        </apex:column>
                                             
                        <apex:column headerValue="{!$ObjectType.Contact.fields.Title.label}" >
                            <apex:outputText >{!c.con.Title}&nbsp;</apex:outputText>
                        </apex:column>
                       
                        <apex:column headerValue="{!$ObjectType.Contact.fields.Email.label}" >
                            <apex:outputText >{!c.con.Email}&nbsp;</apex:outputText>
                        </apex:column>
                       
                        <apex:column headerValue="{!$ObjectType.Contact.fields.Phone.label}" >
                            <apex:outputText >{!c.con.Phone}&nbsp;</apex:outputText>
                        </apex:column>
                       
                        <apex:column headerValue="{!$ObjectType.Contact.fields.Employed_By__c.label}" >
                            <apex:outputText >{!c.con.Employed_By__c}&nbsp;</apex:outputText>
                        </apex:column>
                       
                        <apex:column headerValue="{!$ObjectType.Contact.fields.TD_Use_Account_Address__c.label}" value="{!c.con.TD_Use_Account_Address__c}" />
                    </apex:pageblocktable>
                  </apex:facet>
               </apex:actionStatus>
        </apex:outputPanel>   
    </apex:pageblock>
    <script>
    function checkAll(cb)
    {
        var inputElem = document.getElementsByTagName("input");
        for(var i=0; i<inputElem.length; i++)
        {
            if(inputElem[i].id.indexOf("checkedone")!=-1)
            inputElem[i].checked = cb.checked;
        }
    }   
    </script>
   
    <script>
    if(arrCheckbox != null && arrCheckbox.length > 0){
       for(var i = 0; i < arrCheckbox.length; i++)
       {
          if(arrCheckbox[i].checked)
           {
              isAllChecked = true;
           }
           else
           {
               isAllChecked = false;
               break;
           }
        }
     }
     if(objHeaderCheckbox != '')
     {
         document.getElementById(objHeaderCheckbox).checked = isAllChecked;
     }
     function checkUncheck(obj, comp){
        objHeaderCheckbox = comp;
        if(obj.checked)
        {
            if(arrCheckbox != null && arrCheckbox.length > 0)
            {
                for(var i = 0; i < arrCheckboxForCIC.length; i++)
                {
                    arrCheckboxForCIC[i].checked = true;
                }
            }
        }
        else
        {
            if(arrCheckbox != null && arrCheckbox.length > 0)
            {
                 for(var i = 0; i < arrCheckbox.length; i++)
                 {
                    arrCheckbox[i].checked = false;
                 }
            }
          }
     }                               
     function chechUncheckHeader(obj, headerComp)
     {                                
          if(!obj.checked)
          {
              if(objHeaderCheckbox != null && objHeaderCheckbox != '')
              document.getElementById(objHeaderCheckbox).checked = false;
          }  
      }
    </script> 
    </apex:form>
</apex:page>

 

Andrei KuznetsovAndrei Kuznetsov

****************************************************Class****************************************************************

public class TD_ContactsAddressController
{
    public List<contactwrapper> contactList = new List<contactwrapper>();
    public List<Contact> selectedContacts = new List<Contact>();
    // Sorting
    List<Contact> sortContacts = new List<Contact>();
    public String sortField {get; set;}
    public String previousSortField {get; set;}
    private PageReference accountPage;
    public List<contactwrapper> lstFinalContactWrapper = new List<contactwrapper>();
   
    //Constructor
    public TD_ContactsAddressController(ApexPages.StandardController controller){
         chkValuesContact();
    }
       
    public List<contactwrapper> getContacts()
    {
        lstFinalContactWrapper= new List<contactwrapper>();
        if(!sortContacts.isEmpty()){
            for(Contact objCon: sortContacts){
                contactwrapper objFinalContact = new contactwrapper(objCon);
                lstFinalContactWrapper.add(objFinalContact);
            }
        }
        if(!lstFinalContactWrapper.isEmpty())
        {
            return lstFinalContactWrapper;
        }
        else{return null;}
    }
   
    public PageReference getSelected()
    {
        selectedContacts.clear();
        for(contactwrapper conwrapper : contactList)
        if(conwrapper.selected == true)
        selectedContacts.add(conwrapper.con);
        return null;
    }
   
    public List<Contact> GetSelectedContacts()
    {
        if(selectedContacts.size()>0)
        return selectedContacts;
        else
        return null;
    }   
   
    public class contactwrapper
    {
        public Contact con{get; set;}
        public Boolean selected {get; set;}
        public String ContactURL {get;set;}
        public contactwrapper(Contact c)
        {
            con = c;
           ;
            ContactURL = '/' + c.Id;
        }
    }
   
    //Sorting.
    public void doSort(){
        String order = 'asc';        
        /*This checks to see if the same header was click two times in a row, if so it switches the order.*/
        if(previousSortField == sortField){
            order = 'desc';
            previousSortField = null;
         }else{
             previousSortField = sortField;
         }      
         //To sort the table we simply need to use this one line, nice!
         superSort.sortList(sortContacts, sortField, order);
     }   
   
    // Update Contacts
    //public PageReference doUpdateAddress(){
    public void doUpdateAddress(){
        for (Contact c : selectedContacts)
        {
            c.TD_Use_Account_Address__c = true;
        }
       
        try {
          update selectedContacts;         
          }
        catch (DmlException e) {
          ApexPages.addMessages(e);
          }
        //return new PageReference('/'+ ApexPages.currentPage().getParameters().get('id'));       
    }
   
    public PageReference chkValuesContact(){
        for(Contact c : [SELECT Name, Title, Email, Phone, Employed_By__c, TD_Use_Account_Address__c,
        LastName from Contact where AccountId = :Apexpages.Currentpage().getparameters().get('Id') ORDER BY Name ASC])
        {          
            sortContacts.add(c);
            System.debug('sortContacts: ' + sortContacts);
            contactList.add(new contactwrapper(c));
            System.debug('contactList: ' + contactList);        
        }
        return null;
    }
 }

rmehrmeh

 

Hi,


I would first of all like to ask you certain questions:


  • Is your method getSelected() getting invoked?
  • If yes, Kindly debug the value of selectedContacts which you are returning while updating.
  • For sorting, it is taking "ASC" into consideration as we have passed the order for the 1st as String order = 'asc'. Change it if you want to set the 1st time order as "DESC" and accordingly your below code migth change.  
  • if(previousSortField == sortField){
                order = 'desc';
                previousSortField = null;
             }else{
                 previousSortField = sortField;
             }  
  • For clearing of selectAll CheckBox, there were minor errors in javascript, please correct it accordingly in your code:


                    <apex:column headerValue="" id="clchkBox" rendered="true" width="5%">   
                    <apex:facet name="header">
                    <apex:inputCheckbox id="chkHeader" onclick="checkUncheck(this, '{!$Component.chkHeader}')">                             
                    </apex:inputCheckbox>                       
                    </apex:facet>          
                    <apex:inputCheckbox id="chkChild" value="{!c.selected}" onclick="chechUncheckHeader(this, '{!$Component.chkHeader}')">
                    </apex:inputCheckbox>

 

=====================JAVASCRIPT PART===========================================

 

   function checkUncheck(obj, comp){
        objHeaderCheckbox = comp;
        if(obj.checked)
        {
            if(arrCheckbox != null && arrCheckbox.length > 0)
            {
                for(var i = 0; i < arrCheckbox.length; i++)
                {
                    arrCheckbox[i].checked = true;
                }
            }
        }

=========================================================================

 

  • Hey just install Web Developer Add-on for Mozilla. It will help you locate the javascript error if any.
Andrei KuznetsovAndrei Kuznetsov

My apologies for the late response. My primary job here is support for another CRM, so was full-time on that one. Here are my findings. Every attempt to reorder callse GetContacts twice. Also, after update is done, CheckAll box is not cleared, 'selectedContacts' list is always empty and 'contactList' always contain all Contacts for the Account, regardless if they are selected or not.

 

Thank you,

rmehrmeh

Hi,

 

First of all, i was also in doubt whether select 'selectedContacts' contains value, thats why i asked you.

However i dont know why the getContacts() is being called twice.

Are you using rerender attribute twice? This is the only possibilty i can think of.

Apart from that in the getSelectedFunction iterate "lstFinalContactWrapper" list instead of  "contactList" list and check after putting debug values check whether you get values in selectedContacts.

 

The value should come here as you are using the above list while you are updating the records.

 

Let me know after making changes, it works or not.

 

This was selected as the best answer
Andrei KuznetsovAndrei Kuznetsov

I only use rerender on resorting and when 'Update button' is clicked. Nevertheless, I got rid from both rerender statements and getContacts() still called twice. So, rerender has nothing to do with it. It has to be the Class code is stractured.

 

As you suggested, I iterate now withIstFinalContactWrapper list, and selectedContacts are still empty.

 

You have mentioned that it was working in your system. Could you please send me your code? Accounts and Contacts are standard salesforce objects, so it should work for me as well.

 

Thank you.