0

I have created attachment info object and using wrapper class to store attachment related information. I have created visual force page to display attachment with attachment information using wrapper class. I am sorting this records using compareTo method. However result on this page is not sorting. And displaying records in random order.

My class is as below.

global class AttachmentList {

    public Case complaint {get;set;}
    public List<Attachment> attachmentList {get;set;}
    public List<AtachmentInfo__c> attachmentInfoList {get;set;}
    public List<CategorizedAttachment> categorizedAttachmentList {get;set;}



    public AttachmentList(ApexPages.StandardController controller)
    {
        complaint = (Case)controller.getRecord();

        categorizedAttachmentList = new List<CategorizedAttachment>();

         //Query for all the attachments on this Case
        attachmentList = new List<Attachment>([SELECT Name, Id, CreatedDate, CreatedBy.Name, CreatedById, ParentId 
                                               FROM Attachment WHERE ParentId = :complaint.Id]);

        Set<Id> attachmentIds = (new Map<Id, Attachment>(attachmentList)).keySet();

        //Query for all info objects on any attachments returned
        attachmentInfoList = new List<AtachmentInfo__c> ([SELECT AttachmentIdText__c, Attachment_Title__c, Attachment_Type__c, Attachment_Description__c,Order__c 
                                                          FROM AtachmentInfo__c 
                                                          WHERE AttachmentIdText__c IN :attachmentIds]);

        Map<String, AtachmentInfo__c> attachmentInfoMap  = new Map<String, AtachmentInfo__c>();

        //Build map from list so we can call containsKey()..
        for(AtachmentInfo__c attachmentInfoRecord : attachmentInfoList)
        {
            attachmentInfoMap.put(attachmentInfoRecord.AttachmentIdText__c, attachmentInfoRecord);

        }

        //Loop over attachments and check for matching info objects, if any are missing - create them.
        for(Attachment attachmentRecord : attachmentList)
        {
            //If we find a match, then we know the attachment has been previously categorized
            if(attachmentInfoMap.containsKey(attachmentRecord.Id))
            {
                attachmentInfoMap.get(attachmentRecord.Id).case__c = complaint.Id;
                //create inner class object to represent pairing of both objects
                CategorizedAttachment categorizedAttachment = new CategorizedAttachment (attachmentRecord, attachmentInfoMap.get(attachmentRecord.Id));
                categorizedAttachmentList.add(categorizedAttachment);
                categorizedAttachmentList.sort();
                //If no info obj exists
            }
            else{

                //create one
                CategorizedAttachment categorizedAttachment = new CategorizedAttachment (attachmentRecord, new AtachmentInfo__c(Case__c = complaint.Id));
                categorizedAttachmentList.add(categorizedAttachment);
                categorizedAttachmentList.sort();
            }

        }

    }

    //Inner class to represent a pairing of attachment and attachmentInfo objects
    global class CategorizedAttachment implements Comparable
    {
        public Attachment attachment {get;set;}
        public AtachmentInfo__c attachmentInfo {get;set;}
        public Decimal order;

        public CategorizedAttachment()
        {      

        }
        //Inner class constructor accepts both objects and parents the info obj to the attachment
        public CategorizedAttachment (Attachment attachInput, AtachmentInfo__c attachInfoInput)
        {
            order = attachInfoInput.Order__c;
            attachment = attachInput;

            attachmentInfo = attachInfoInput;

            attachmentInfo.AttachmentIdText__c = attachment.Id;    


        }  

        global Integer compareTo(Object compareTo){
            CategorizedAttachment compareToAttachment = (CategorizedAttachment)compareTo;
            if(order == compareToAttachment.order ) return 0;
            if(this.order > compareToAttachment.order ) return 1;
            return -1;
    }


    }

}

And Visualforce Page:

<apex:page standardController="Case" extensions="AttachmentList" sidebar="false" showHeader="false">
<apex:form >
    <apex:pageMessages />
    <!-- This outputPanel will give us scrollbars -->
    <!--  <apex:outputPanel layout="block" style="overflow:auto;width:750px;height:250px" >-->
    <apex:outputPanel layout="block" style="overflow:auto;height:450px" >
        <apex:pageBlock title="Attachments List" id="block1">
            <apex:pageBlockTable value="{!categorizedAttachmentList}" width="100%" var="category" >

                <apex:column >
                    <apex:outputLink target="_blank" value="/servlet/servlet.FileDownload?file={!category.attachment.Id}"> Preview </apex:outputLink>
                </apex:column>

                <apex:column >
                    <apex:facet name="header">Attachment Title</apex:facet>
                    <apex:outputText value="{!category.attachmentInfo.Attachment_Title__c}"/>
                </apex:column>

                <apex:column >
                    <apex:facet name="header">Description</apex:facet>
                    <apex:outputText value="{!category.attachmentInfo.Attachment_Description__c}" />
                </apex:column>


                <apex:column >
                    <apex:facet name="header">Order</apex:facet>
                    <apex:outputText value="{!category.attachmentInfo.Order__c}" />
                </apex:column>

                <apex:column >
                    <apex:facet name="header">Attachment Name</apex:facet>
                    <apex:outputText value="{!category.attachment.Name}"/>
                </apex:column>

                <apex:column >
                    <apex:facet name="header">Created By</apex:facet>
                    <apex:outputText value="{!category.attachment.CreatedBy.Name}"/>                        
                </apex:column>                  

                <apex:column >
                    <apex:facet name="header">Created Date</apex:facet>
                    <apex:outputText value="{0,date,MM/dd/yyyy HH:mm aaa}" >
                        <apex:param value="{!category.attachment.CreatedDate}"/>
                    </apex:outputText>          
                </apex:column>

            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:outputPanel>
</apex:form>    

I am not getting any compile time error but the result is unsorted. Please look at the screenshot below.

Rendered Records

2 Answers 2

2

You do need to handle nulls, but I would use a slightly different algorithm than what is already posted. First of all, here's a demonstration that this is expected behavior:

class Demo implements Comparable
{
    Integer order;
    public Demo(Integer order) { this.order = order; }
    public Integer compareTo(Object instance)
    {
        Demo that = (Demo)instance;
        if (this.order == that.order) return 0;
        if (this.order > that.order) return 1;
        return -1;
    }
}

List<Demo> sorted = new List<Demo>
{
    new Demo(1),
    new Demo(2),
    new Demo(null),
    new Demo(1),
    new Demo(null)
};
sorted.sort();
system.debug(JSON.serialize(sorted));

This anonymous script yields:

[{"order":1},{"order":2},{"order":null},{"order":1},{"order":null}]

Now, here's how I would fix it. My guess is you would want nulls last, so change compareTo as follows:

public Integer compareTo(Object instance)
{
    Demo that = (Demo)instance;
    if (this.order == that.order) return 0;

    if (this.order == null) return 1;
    if (that.order == null) return -1;

    return (this.order > that.order) ? 1 : -1;
}

This updated script yields:

[{"order":1},{"order":1},{"order":2},{"order":null},{"order":null}]

2
  • Thanks for your reply Adrain. That solves my problem. However Using above code null values are at top not at the bottom? I am not sure why? I can see we are returning 1 but still its at top befor all numbers, Do you know why?
    – Ricky
    Commented May 30, 2017 at 20:48
  • Hmm, that's not the behavior in the simpler example. I'm not sure why nulls would show first in your UI.
    – Adrian Larson
    Commented May 30, 2017 at 21:25
2

You need to incorporate null checking when you are comparing in compareTo method

global Integer compareTo(Object compareTo){
        CategorizedAttachment compareToAttachment = (CategorizedAttachment)compareTo;
        if(this.order !=null && compareToAttachment.order != null 
            && Integer.valueOf(this.order) == Integer.valueOf(compareToAttachment.order))
        {
            return 0;
        }
        if(this.order !=null && compareToAttachment.order != null 
                && Integer.valueOf(this.order) > Integer.valueOf(compareToAttachment.order))
        {
            return 1;
        }
        return -1;

}
2
  • This code handles nulls somewhat arbitrarily though. I recommend giving them their own clauses to make it clear whether you want nulls first or last.
    – Adrian Larson
    Commented May 30, 2017 at 20:20
  • Thanks a lot Santanu Boral. Your answer is very appropriate to my question, As i didn't mention I want set order by keeping Null's in mind too. However now I know and want handle null so I ended up using Adrian's answer. Thank you so very much though.
    – Ricky
    Commented May 30, 2017 at 20:51

You must log in to answer this question.

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