1

I have implemented a Wrapper class using this: Salesforce Wrapper Class. Now I am trying to implement sorting for the column header which turns out to be throwing error:

Invalid field Account.Name for Contact. Error is in expression '{!sortWrpLst}' in page myVfWrapperPage: Class.myWrapper.cContact.compareTo: line **, Column 1 Class: Class.myWrapper.cContact. sortWrpLst: line **, Column 1

An unexpected error has occurred. Your development organization has been notified.

Visualforce Page:

<apex:page standardController="Case" extensions="myWrapper" tabStyle="Create_New_Incident__tab">
<apex:form >
    <apex:pageMessages />
    <apex:pageBlockTable value="{!contacts}" var="c" id="table">
        <apex:column >
            <apex:facet name="header">
                <apex:inputCheckbox onclick="selectCheckboxes(this,'inputId')"/>
            </apex:facet>
            <apex:inputCheckbox value="{!c.selected}" id="inputId"/>
        </apex:column>
        <apex:column>
            <apex:facet name="header">
                <apex:commandLink value="Name {!IF(compareField=='Name',IF(sortOrder='asc','▼','▲'),'')}" action="{!sortWrpLst}">  
                    <apex:param name="compareField" value="Name" assignTo="{!compareField}" />  
                    <apex:param name="orderType" value="{!IF(sortOrder='asc', 'desc', 'asc')}" assignTo="{!sortOrder}" />  
                </apex:commandLink> 
            </apex:facet>
            <apex:outputField value="{!c.con.Name}"/>
        </apex:column>
        <apex:column>
            <apex:facet name="header">
                <apex:commandLink value="Hospital {!IF(compareField=='Account.Name',IF(sortOrder='asc','▼','▲'),'')}" action="{!sortWrpLst}">  
                    <apex:param name="compareField" value="Account.Name" assignTo="{!compareField}" />  
                    <apex:param name="orderType" value="{!IF(sortOrder='asc', 'desc', 'asc')}" assignTo="{!sortOrder}" />  
                </apex:commandLink> 
            </apex:facet>
            <apex:outputField value="{!c.con.Account.Name}"/>
        </apex:column>
    </apex:pageBlockTable>
</apex:form>

Class:

public class myWrapper{
public List<cContact> contactList {get; set;}
public static String compareField {get; set;} 
public static String sortOrder{get; set;}

public myWrapper(){
    getContacts();
}

public List<cContact> getContacts() {
    List<Contact> conList = [SELECT Id, Name, Email, Phone, Account.Name FROM Contact WHERE Checkbox__c = TRUE ];
    contactList = new List<cContact>();
    for(Contact c: conList) {
        contactList.add(new cContact(c, false));
    }
    return contactList;
}


public void sortWrpLst() {  
    contactList.sort();  
}

public class cContact implements Comparable {
    public Contact con {get; set;}
    public Boolean selected {get; set;}

    public cContact(Contact c, boolean selectedBox) {
        con = c;
        selected = selectedBox;
    }
    public Integer compareTo(Object vCase)  
    {  
        cContact caseToComp = (cContact)vCase;
        if((String)con.get(compareField) > (String)caseToComp.con.get(compareField)){  
            return sortOrder.equals('asc') ? 1 : 0;  
        }
        else {
            return sortOrder.equals('asc') ? 0 : 1; 
        }
    } 
}  
}

Referred: Dynamic Sorting

1
  • 1
    Since you're not using pagination, probably better to do column sorting client side. There are many good Javascript libraries out there for this purpose which are already written and well tested.
    – Adrian Larson
    Commented Dec 19, 2017 at 20:51

2 Answers 2

2

You should just do this sorting client side. There are plenty of solutions to this problem already out there. But the reason you're getting the error is you're basically trying to do:

String accountName = someContact.get('Account.Name');

If you want to support cross object fields, you need to take a different approach. If you implement a CrossObject class like I posted in this answer, you could just do:

String accountName = CrossObject.get(someContact, 'Account.Name');

That said, your algorithm is not very efficient, or maybe not even correct. You should be returning -1 somewhere as part of your compareTo implementation, to indicate when one record should go before the other. Return 1 when it should go after, and 0 when they are equivalent. All three return values should be used in just about any sane sorting algorithm.

7
  • Whoever down-voted care to explain why?
    – Adrian Larson
    Commented Dec 19, 2017 at 22:11
  • Hi Adrian, I couldn't able to use this String accountName = CrossObject.get(someContact, 'Account.Name'); as I am dynamically applying different compareField values as the process of clicking on the column headers. Can you please narrow it down for me? Thanks.
    – SatyaV
    Commented Dec 20, 2017 at 15:42
  • Even column header: Name is clickable, but the values in the column are not getting sorted. What might be I am doing wrong?
    – SatyaV
    Commented Dec 20, 2017 at 15:44
  • Yeah man you would us compareField instead...or just use Javascript.
    – Adrian Larson
    Commented Dec 20, 2017 at 16:17
  • I am getting an error by using this: String accountName = con.AccountId.get(con, 'Account.Name');. Also I have tried this: String accountName = Account.get(con, 'Account.Name');. Error: Method does not exist or incorrect signature: void get(Contact, String) from the type Account
    – SatyaV
    Commented Dec 20, 2017 at 17:42
0

You can leverage JQuery datatable for this kind of functionality where sorting, pagination, searching in the list can be possible.

Here is my poc where list can handle 10000 records.

Class

public with sharing class SortWrapper 
{

    public List<ContactInfoWrapper> ContactsWrapper {get; set;}    
    //added for paginnation
    public List<List<ContactInfoWrapper>> listofContactsWrapper {get; set;}

    public SortWrapper()
    {
        ContactsWrapper = new List<ContactInfoWrapper>();
        listofContactsWrapper = new List<List<ContactInfoWrapper>>();
        getContacts();
    } 

    public void getContacts()   
    {
        for(Contact s:[SELECT Id, Name, Email, Phone, Account.Name FROM Contact])
        {            
            ContactsWrapper.add(new ContactInfoWrapper(s)); 
            if(ContactsWrapper.size() == 999)
            {
                listofContactsWrapper.add(ContactsWrapper);
                ContactsWrapper= new List<ContactInfoWrapper>();
            }                
        } 
        if(ContactsWrapper.size() != 0){
            listofContactsWrapper.add(ContactsWrapper);
        }   

    }

    //Wrapper class
    public class ContactInfoWrapper
    {
        public Contact sObj{get;set;}
        public Boolean checked {get;set;}
        public ContactInfoWrapper(Contact con)
        {
            sObj = con;  
            checked=false;  
        } 
    }
}

Visualforce

<apex:page id="SortPage" controller="SortWrapper"  showHeader="false">
    <!--added for pagination-->
       <head>
        <apex:includescript value="//code.jquery.com/jquery-1.11.1.min.js" / >
        <apex:includescript value="//cdn.datatables.net/1.10.4/js/jquery.dataTables.min.js" />
        <apex:stylesheet value="//cdn.datatables.net/1.10.4/css/jquery.dataTables.css" />
        <script>
            j$ = jQuery.noConflict();
            j$(document).ready( function () {
                var contactTable = j$('[id$="contacttable"]').DataTable({

                });
            });
        </script>
    </head>
   <!---End of Pagination--->

    <apex:form id="myForm">

        <apex:sectionHeader title="Contact"/><br/>

        <apex:pageBlock>

            <apex:pageBlockSection title="Contact Records" collapsible="false" columns="1"/>
            <br></br>
            <body>                
                <table id="contacttable" class="display">       
                    <thead>
                        <tr>
                            <th style="width:10%;">Select</th>
                            <th style="width:25%;">Name</th>
                            <th style="width:30%;">Account Name</th>                                
                        </tr>
                    </thead>
                    <tbody>
                        <apex:repeat value="{!listofContactsWrapper}" var="contactinfowrp" id="removeTableInd">
                              <apex:repeat value="{!contactinfowrp}" var="con">
                               <tr >
                                  <td><apex:inputCheckbox value="{!con.checked}"/></td>
                                  <td>{!con.sObj.Name}</td>
                                  <td>{!con.sObj.Account.Name}</td>
                              </tr>
                            </apex:repeat>
                        </apex:repeat>
                    </tbody>
                </table>
            </body>
        </apex:pageBlock>  
    </apex:form>
</apex:page>

Outcome

contact sort

3
  • Can you please make me understand where(line number) exactly you have implemented the column header sorting?
    – SatyaV
    Commented Dec 19, 2017 at 21:40
  • it is done by the library itself, refer j$(document).ready function Commented Dec 19, 2017 at 21:49
  • Can you help me fixing the error within my code?
    – SatyaV
    Commented Dec 19, 2017 at 22:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .