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
Rajesh ShahRajesh Shah 

Case Comments Related List using Visualforce

Recently I was working on a requirement which required overriding the Case detail page with a visualforce page. Problem crept when the related list comonent didnt worked for Case Comments and History. So I decided to write my own code to display the related lists.

I was finally able to write my own code to display the related list. It implements all the function that standard related list of Case Comments provide. In order to make it reusable, I made it as a component so that in other pages I just need to pass the Case Id and I will get the complete list of Case Comments.

 Heres the code finally :

 1. Component Code

 

<apex:component controller="CaseCommentsComponentController" allowDML="true">
<!-- Attribute Definition -->
<apex:attribute name="CaseId" description="Salesforce Id of the Case whose Case Comments needs to be rendered" type="Id" required="true" assignTo="{!caseId}" />

<!-- Component Body -->
<apex:componentBody >
<apex:form >
<apex:pageBlock title="Case Comments" >
<apex:pageBlockButtons location="top">
<apex:commandButton action="{!NewComment}" value="New"/>
</apex:pageBlockButtons>
<apex:pageBlockTable value="{!Comments}" var="comment">
<apex:column headerValue="Action">
<apex:outputLink value="/{!comment.cComment.Id}/e?parent_id={!caseId}&retURL=/{!caseId}">Edit</apex:outputLink>&nbsp | &nbsp
<apex:commandLink action="{!deleteComment}" value="Del">
<apex:param name="CommentId_d" value="{!comment.cComment.Id}"/>
</apex:commandLink>&nbsp | &nbsp
<apex:commandLink action="{!makePublicPrivate}" value="{!comment.PublicPrivateAction}">
<apex:param name="CommentId_p" value="{!comment.cComment.Id}" />
</apex:commandLink>
</apex:column>
<apex:column headerValue="Public" value="{!comment.cComment.IsPublished}" />
<apex:column headerValue="Comments">
<apex:outputText escape="false" value="{!comment.commentText}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>
</apex:componentBody>
</apex:component>

 

 2. Apex Code

public with sharing class CaseCommentsComponentController {

public Id caseId {get; set;}
public cComments[] comments{
get{
List<cComments> comments = new List<cComments>();
for(CaseComment comment : [Select LastModifiedDate, LastModifiedBy.Id, LastModifiedBy.Name, IsPublished, CreatedDate, CreatedBy.Id, CreatedBy.Name, CommentBody From CaseComment c where ParentId = :caseId order by c.LastModifiedDate desc])
{
cComments tempcComment = new cComments();
tempcComment.cComment = comment;

// Build String to display.
tempcComment.commentText = '<b>Created By: <a href=\'/' + comment.CreatedBy.Id + '\'>' + comment.CreatedBy.Name + '</a> (' + comment.CreatedDate.format() + ') | ';
tempcComment.commentText += 'Last Modified By: <a href=\'/' + comment.LastModifiedBy.Id + '\'>' + comment.LastModifiedBy.Name + '</a> (' + comment.LastModifiedDate.format() + ')</b><br>';
tempcComment.commentText += comment.CommentBody;

if(comment.IsPublished)
tempcComment.PublicPrivateAction = 'Make Private';
else
tempcComment.PublicPrivateAction = 'Make Public';
//Add to list
comments.add(tempcComment);
}
return comments;
}

set;
}

public PageReference NewComment()
{
PageReference pr = new PageReference('/00a/e?parent_id='+ caseId + '&retURL=%2F' + caseId);
pr.setRedirect(true);
return pr;
}

public PageReference deleteComment()
{
Id commentId = ApexPages.currentPage().getParameters().get('CommentId_d');

for(cComments Comment : comments)
{
if(Comment.cComment.Id == commentId)
{
delete Comment.cComment;
break;
}
}

PageReference pg = new PageReference('/' + caseId);
pg.setRedirect(true);
return pg;
}

public PageReference makePublicPrivate()
{
Id commentId = ApexPages.currentPage().getParameters().get('CommentId_p');
for(cComments Comment : comments)
{
if(Comment.cComment.Id == commentId)
{
Comment.cComment.IsPublished = !Comment.cComment.IsPublished;
if(Comment.cComment.IsPublished)
Comment.PublicPrivateAction = 'Make Private';
else
Comment.PublicPrivateAction = 'Make Public';

update Comment.cComment;
break;
}
}
PageReference pg = new PageReference('/' + caseId);
pg.setRedirect(true);
return pg;
}

public class cComments {

public CaseComment cComment {get; set;}
public String commentText {get; set;}
public String PublicPrivateAction {get; set;}
}
}

 Hope it is helpful to you.

 Let me know your views on the code above or if you have any questions

Message Edited by Rajesh Shah on 10-16-2009 08:03 PM
kminevkminev

Rajesh.

 

This great you put this component together.

 

Couple questions and issues I have with it:

 

 I embeded your component as follows:

<apex:page standardController="Case"> <c:CaseCommentRelatedList CaseId="{!Case.Id}"/> </apex:page>  

 

Then I added this visual force page to my case standard Page Layout as a separate section. The problem is that it displays only several comments and if I do have more comments and longer in length then it will not work for me.

 

Any ideas...perhaps I don't embed your component properly?

 

Thank you

 

Rajesh ShahRajesh Shah

You mean that if there are 10-15 comments but you want to display only the last 5 or something like that?

 

Well pageBlockTable has a attribute called rows. You can set that to the number you want.

kminevkminev

No actually the way around. If I have 2 rows of comments they display fine, however if I have more comments they don't display on the page.

 

is there a property for a scroll bar I can set for example if the content exceeds the size of the page I can set the scroll bar.

kminevkminev

I have a question about your code.

 

The following line:  

 

public cComments[] comments{
get{

 

What class type is cComments I don't understand? Is it a dynamic class that you create on the fly to place you temp variables?

 

I tried to re-create your cComments class type in a different code and place some dynamic variabl, but didn't work.

 

Can you please explain and correct me where I am wrong.

 

Thanks in advance.

 

 

kminevkminev
Sorry I noticed couple block of code below you have a class declaration.
Mike.KatulkaMike.Katulka

Rajesh, Thanks for this component!

 

For anyone needing a Unit Test in order to push into production, I have created the following unit test.  Feel free to use this with Rajesh's original posted component code.

 

@isTest
public class CaseCommentsControllerTester {
 static testMethod void myTestCaseComments() {
        
        //100% code coverage
        //Unit test by: Mike Katulka @ www.itedgecrm.com - mike@itedgecrm.com
        //Component by: http://boards.developerforce.com/t5/forums/replypage/board-id/Visualforce/message-id/17704
        
		//Navigate to Case page
        PageReference pageRef = Page.CaseView;     //**** Enter your Case overridden view page name here  
        		
        //Create test Case
		Case c = new Case(RecordTypeId = [Select Id from RecordType where DeveloperName='Question' and sObjectType = 'Case' limit 1].id, 
		  Description='UNIT TESTING',
		  Origin='Phone',
		  Priority='Medium',
		  Status='New'
		  );				
		insert c;
		system.assertEquals(1, [select id from case where id=:c.id and isdeleted=false].size());
		
		//create controller first
		CaseCommentsComponentController controller = new CaseCommentsComponentController();
		Test.setCurrentPage(pageRef);
		controller.caseid = c.id;
		
		//Test NewComment()
		String nextPage = controller.NewComment().getUrl();		
		system.assertEquals(true, nextPage.contains('/00a/e?parent_id=' + c.id)); //Verify that it sends you to the Standard casecomment SF page
		
		//Create a casecomment for further testing
		CaseComment cc = new CaseComment (ParentID = c.id, CommentBody = 'UNIT TESTING', isPublished=false);
		insert cc;
		system.assertNotEquals(null, cc.id);
		string commentid = cc.id;		
		
		//Test makePublicPrivate()  > to public
		Test.setCurrentPage(pageRef);		
        ApexPages.currentPage().getParameters().put('CommentId_p', commentid); //parameter name = CommentId_p		
		nextPage = controller.makePublicPrivate().getUrl();
		system.assertEquals(true, nextPage.contains('/' + c.id));
		system.assertEquals(1, [select id from casecomment where id=:commentid and isdeleted=false and isPublished=true].size());		
		
		//Test makePublicPrivate()  > to private
		Test.setCurrentPage(pageRef);		
        ApexPages.currentPage().getParameters().put('CommentId_p', commentid); //parameter name = CommentId_p		
		nextPage = controller.makePublicPrivate().getUrl();
		system.assertEquals(true, nextPage.contains('/' + c.id));
		system.assertEquals(1, [select id from casecomment where id=:commentid and isdeleted=false and isPublished=false].size());
		
		//Test deleteComment()
		Test.setCurrentPage(pageRef);		
        ApexPages.currentPage().getParameters().put('CommentId_d', commentid); //parameter name = CommentId_d (different!)	
		nextPage = controller.DeleteComment().getUrl();
		system.assertEquals(true, nextPage.contains('/' + c.id));
		system.assertEquals(0, [select id from casecomment where id=:commentid and isdeleted=false].size());	
		
    }
        
}

 

Mike Katulka

www.itedgecrm.com

IT Edge CRM, Inc.

CharlieLangCharlieLang

Hi, this code is brilliant, i am using it in a service cloud setup and have replaced the interaction panel with this.

 

I just have one question, is there a way of modifying the "new" button so that when it's clicked it opens in a new window? or the main page in the the service cloud?

 

<apex:pageBlockButtons location="top">
<apex:commandButton action="{!NewComment}" value="New"/>
</apex:pageBlockButtons>

 

RajeshShah.ax1315RajeshShah.ax1315

You can use CommandLink and targer = "_blank" to open a new window. Later, you can also style the link as button.

CharlieLangCharlieLang

The "_blank" seems to work fine as a commandlink but is there a way of doing this as a commandbutton?

CharlieLangCharlieLang

am i able to add it in the page ref in the class? in this bit?

 

public PageReference NewComment()
    {
        PageReference pr = new PageReference('/00a/e?parent_id='+ caseId + '&retURL=%2F' + caseId );
        pr.setRedirect(true);
        return pr;
    }

 

RajeshShah.ax1315RajeshShah.ax1315

As far as I know, it is not possible. You can do one more thing. From commandButton, call apex function with pagereference null. Use oncomplete event of commandButton to call JS function and open the new window from there.

carloecarloe

this is a great code. thanks for this!

 

one question though:

we're trying to put this into a Force.com public site.

 

The public access settings (profile) doesnt allow for Case Editing. Only Read and Create.

 

Will creating a new comment from a Force.com site work?

RitchiebRitchieb

Hi

 

I'm trying to use this test class and it is not passing. The apex class works and I can use it on a page in my sandbox but if anyone could tell me why the test isnt completeing that would be great.

 

Apex class

 

public with sharing class CaseCommentsComponentController {
    
    public Id caseId {get; set;}
    public cComments[] comments{
        get{
            List<cComments> comments = new List<cComments>();
            for(CaseComment comment : [Select LastModifiedDate, LastModifiedBy.Id, LastModifiedBy.Name, IsPublished, CreatedDate, CreatedBy.Id, CreatedBy.Name, CommentBody From CaseComment c where ParentId = :caseId order by c.LastModifiedDate desc])
            {
                cComments tempcComment = new cComments();
                tempcComment.cComment = comment;
                
                // Build String to display.
                tempcComment.commentText = '<b>Created By: <a href=\'/' + comment.CreatedBy.Id + '\'>' + comment.CreatedBy.Name + '</a> (' + comment.CreatedDate.format() + ') | ';
                tempcComment.commentText += 'Last Modified By: <a href=\'/' + comment.LastModifiedBy.Id + '\'>' +  comment.LastModifiedBy.Name + '</a> (' + comment.LastModifiedDate.format() + ')</b><br>';
                tempcComment.commentText += comment.CommentBody;
                
                if(comment.IsPublished)
                    tempcComment.PublicPrivateAction = 'Make Private';
                else
                    tempcComment.PublicPrivateAction = 'Make Public';
                //Add to list
                comments.add(tempcComment); 
            }
            return comments;
        }
        
        set;
    }
        
    public PageReference NewComment()
    {
        PageReference pr = new PageReference('/00a/e?parent_id='+ caseId + '&retURL=%2F' + caseId);
        pr.setRedirect(true);
        return pr;
    }
    
    public PageReference deleteComment()
    {
        Id commentId = ApexPages.currentPage().getParameters().get('CommentId_d');
        
        for(cComments Comment : comments)
        {
            if(Comment.cComment.Id == commentId)
            {   
                delete Comment.cComment;                
                break;
            }
        }
        
        PageReference pg = new PageReference('/' + caseId);
        pg.setRedirect(true);
        return pg;
    }   
    
    public PageReference makePublicPrivate()
    {
        Id commentId = ApexPages.currentPage().getParameters().get('CommentId_p');
        for(cComments Comment : comments)
        {
            if(Comment.cComment.Id == commentId)
            {   
                Comment.cComment.IsPublished = !Comment.cComment.IsPublished;
                if(Comment.cComment.IsPublished)
                    Comment.PublicPrivateAction = 'Make Private';
                else
                    Comment.PublicPrivateAction = 'Make Public';
                    
                update Comment.cComment;                
                break;
            }
        }
        PageReference pg = new PageReference('/' + caseId);
        pg.setRedirect(true);
        return pg;
    }
    
    public class cComments {
    
        public CaseComment cComment {get; set;}
        public String commentText {get; set;}
        public String PublicPrivateAction {get; set;}
    }
}

 Apex Test Class

@isTest
public class CaseCommentsControllerTester {
 static testMethod void myTestCaseComments() {
        
        //100% code coverage
        //Unit test by: Mike Katulka @ www.itedgecrm.com - mike@itedgecrm.com
        //Component by: http://boards.developerforce.com/t5/forums/replypage/board-id/Visualforce/message-id/17704
        
        //Navigate to Case page
        PageReference pageRef = Page.Case;     //**** Enter your Case overridden view page name here  
                
        //Create test Case
        Case c = new Case(RecordTypeId = [Select Id from RecordType where DeveloperName='Question' and sObjectType = 'Case' limit 1].id, 
          Description='UNIT TESTING',
          Origin='Phone',
          Priority='Medium',
          Status='New'
          );                
        insert c;
        system.assertEquals(1, [select id from case where id=:c.id and isdeleted=false].size());
        
        //create controller first
        CaseCommentsComponentController controller = new CaseCommentsComponentController();
        Test.setCurrentPage(pageRef);
        controller.caseid = c.id;
        
        //Test NewComment()
        String nextPage = controller.NewComment().getUrl();     
        system.assertEquals(true, nextPage.contains('/00a/e?parent_id=' + c.id)); //Verify that it sends you to the Standard casecomment SF page
        
        //Create a casecomment for further testing
        CaseComment cc = new CaseComment (ParentID = c.id, CommentBody = 'UNIT TESTING', isPublished=false);
        insert cc;
        system.assertNotEquals(null, cc.id);
        string commentid = cc.id;       
        
        //Test makePublicPrivate()  > to public
        Test.setCurrentPage(pageRef);       
        ApexPages.currentPage().getParameters().put('CommentId_p', commentid); //parameter name = CommentId_p       
        nextPage = controller.makePublicPrivate().getUrl();
        system.assertEquals(true, nextPage.contains('/' + c.id));
        system.assertEquals(1, [select id from casecomment where id=:commentid and isdeleted=false and isPublished=true].size());       
        
        //Test makePublicPrivate()  > to private
        Test.setCurrentPage(pageRef);       
        ApexPages.currentPage().getParameters().put('CommentId_p', commentid); //parameter name = CommentId_p       
        nextPage = controller.makePublicPrivate().getUrl();
        system.assertEquals(true, nextPage.contains('/' + c.id));
        system.assertEquals(1, [select id from casecomment where id=:commentid and isdeleted=false and isPublished=false].size());
        
        //Test deleteComment()
        Test.setCurrentPage(pageRef);       
        ApexPages.currentPage().getParameters().put('CommentId_d', commentid); //parameter name = CommentId_d (different!)  
        nextPage = controller.DeleteComment().getUrl();
        system.assertEquals(true, nextPage.contains('/' + c.id));
        system.assertEquals(0, [select id from casecomment where id=:commentid and isdeleted=false].size());    
        
    }
        
}

 Component

 

<apex:component controller="CaseCommentsComponentController" allowDML="true">
    <!-- Attribute Definition -->
    <apex:attribute name="CasesId" description="Salesforce Id of the Case whose Case Comments needs to be rendered" type="Id" required="true" assignTo="{!caseId}" />
    
    <!-- Component Body -->
    <apex:componentBody >
        <apex:form >
            <apex:pageBlock title="Case Comments" >
                <apex:pageBlockButtons location="top">
                    <apex:commandButton action="{!NewComment}" value="New"/>
                </apex:pageBlockButtons>
                <apex:pageBlockTable value="{!Comments}" var="comment"> 
                    <apex:column headerValue="Action"> 
                        <apex:outputLink value="/{!comment.cComment.Id}/e?parent_id={!caseId}&retURL=/{!caseId}">Edit</apex:outputLink>&nbsp; | &nbsp;
                        <apex:commandLink action="{!deleteComment}" value="Del">
                            <apex:param name="CommentId_d" value="{!comment.cComment.Id}"/>
                        </apex:commandLink>&nbsp; | &nbsp; 
                        <apex:commandLink action="{!makePublicPrivate}" value="{!comment.PublicPrivateAction}">
                            <apex:param name="CommentId_p" value="{!comment.cComment.Id}" />
                        </apex:commandLink>
                    </apex:column>
                    <apex:column headerValue="Public" value="{!comment.cComment.IsPublished}" />
                    <apex:column headerValue="Comments">
                        <apex:outputText escape="false" value="{!comment.commentText}"/>
                    </apex:column>
                </apex:pageBlockTable>
            </apex:pageBlock>   
        </apex:form>    
    </apex:componentBody>
</apex:component>

 

Page

 

<apex:page standardController="Case" showHeader="true"  tabStyle="case" >
            <apex:detail relatedList="false"/>
            <c:CaseComments CasesId="{!Case.Id}"/>
</apex:page>

 

 

If anyone could help this test class pass it would be great.

 

Cheers,

 

Ritchie

 

RitchiebRitchieb

Hi All,

 

Any ideas on this?

 

Kind Regards,

Ritchie

RitchiebRitchieb

Hi All,

 

Nevermide I have worked it out. The problem was with the create case section, it had a record type that didnt exsist and a status that also didnt exsist.

 

@isTest
public class CaseCommentsControllerTester {
 static testMethod void myTestCaseComments() {
        
        //100% code coverage
        //Unit test by: Mike Katulka @ www.itedgecrm.com - mike@itedgecrm.com
        //Component by: http://boards.developerforce.com/t5/forums/replypage/board-id/Visualforce/message-id/17704
        
        //Navigate to Case page
        PageReference pageRef = Page.Case;     //**** Enter your Case overridden view page name here  
                
        //Create test Case - I needed to change the record type name and the status field value from New to a status that exsists in my org.
        Case c = new Case(RecordTypeId = [Select Id from RecordType where DeveloperName='Support_Case' and sObjectType = 'Case' limit 1].id, 
          Subject='UNIT TESTING',
          Description='UNIT TESTING',
          Origin='Phone',
          Priority='Medium',
          Internal_Severity__c='Issue affecting small group of users',
          Status='Logged'
          );                
        insert c;
        system.assertEquals(1, [select id from case where id=:c.id and isdeleted=false].size());
        
        //create controller first
        CaseCommentsComponentController controller = new CaseCommentsComponentController();
        Test.setCurrentPage(pageRef);
        controller.caseid = c.id;
        
        //Test NewComment()
        String nextPage = controller.NewComment().getUrl();     
        system.assertEquals(true, nextPage.contains('/00a/e?parent_id=' + c.id)); //Verify that it sends you to the Standard casecomment SF page
        
        //Create a casecomment for further testing
        CaseComment cc = new CaseComment (ParentID = c.id, CommentBody = 'UNIT TESTING', isPublished=false);
        insert cc;
        system.assertNotEquals(null, cc.id);
        string commentid = cc.id;       
        
        //Test makePublicPrivate()  > to public
        Test.setCurrentPage(pageRef);       
        ApexPages.currentPage().getParameters().put('CommentId_p', commentid); //parameter name = CommentId_p       
        nextPage = controller.makePublicPrivate().getUrl();
        system.assertEquals(true, nextPage.contains('/' + c.id));
        system.assertEquals(1, [select id from casecomment where id=:commentid and isdeleted=false and isPublished=true].size());       
        
        //Test makePublicPrivate()  > to private
        Test.setCurrentPage(pageRef);       
        ApexPages.currentPage().getParameters().put('CommentId_p', commentid); //parameter name = CommentId_p       
        nextPage = controller.makePublicPrivate().getUrl();
        system.assertEquals(true, nextPage.contains('/' + c.id));
        system.assertEquals(1, [select id from casecomment where id=:commentid and isdeleted=false and isPublished=false].size());
        
        //Test deleteComment()
        Test.setCurrentPage(pageRef);       
        ApexPages.currentPage().getParameters().put('CommentId_d', commentid); //parameter name = CommentId_d (different!)  
        nextPage = controller.DeleteComment().getUrl();
        system.assertEquals(true, nextPage.contains('/' + c.id));
        system.assertEquals(0, [select id from casecomment where id=:commentid and isdeleted=false].size());    
        
    }
        
}

 

Krrish GopalKrrish Gopal
Hi All,

I'm try to use this visualforce component at my Saleforce site VF page it's not working, Can anybody tell me how can I use this component at my saleforce site VF page and other case related lists.

Thanks in advanced 
Ravi_SinghRavi_Singh
Hi Guys,

I saw all above comments.
I have created VF page in which i am able to delete casecomment commentbody, but i want to know how can i edit any casecomment and save on same page.