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
    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 Dec 19 '17 at 20:51
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.

  • Whoever down-voted care to explain why? – Adrian Larson Dec 19 '17 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. – Arnold Jr. Dec 20 '17 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? – Arnold Jr. Dec 20 '17 at 15:44
  • Yeah man you would us compareField instead...or just use Javascript. – Adrian Larson Dec 20 '17 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 – Arnold Jr. Dec 20 '17 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

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.