0

Working on creating a tabbed view for cases as opposed to the standard page layout:

<apex:page standardController="Case" sidebar="false">
    <apex:tabPanel switchType="Client">
        <apex:tab id="detailsTab" label="Details">
            <apex:detail relatedList="false"/>
        </apex:tab>
        <apex:tab id="commentsTab" label="Comments">
            <apex:pageBlock >
                <apex:form >
                    <div style="text-align:center;">
                        <apex:commandButton value="New" action="https://na34.salesforce.com/00a/e?parent_id={!Case.Id}&retURL=https://c.na34.visual.force.com/apex/TabbedCase?id={!Case.Id}"/>
                    </div>
                    <apex:pageBlockTable value="{!case.casecomments}" var="c">
                        <!-- https://na34.salesforce.com/{!c.id}/e?parent_id={!Case.Id}&retURL=https://c.na34.visual.force.com/apex/TabbedCase?id={!Case.Id} -->
                        <apex:column headerValue="Actions" width="75">
                            <apex:commandLink value="Edit" action="https://na34.salesforce.com/{!c.id}/e?parent_id={!Case.Id}&retURL=https://c.na34.visual.force.com/apex/TabbedCase?id={!Case.Id}"/> &nbsp;
                            <apex:commandLink value="Delete" action="https://na34.salesforce.com/setup/own/deleteredirect.jsp?delID={!c.Id}&retURL=https://c.na34.visual.force.com/apex/TabbedCase?id={!Case.Id}"/>
                        </apex:column>
                        <apex:column headerValue="Author" width="100">
                            {!c.createdby.Name}
                        </apex:column>
                        <apex:column headerValue="Comment">
                            {!c.commentbody}
                        </apex:column>
                    </apex:pageBlockTable>
                </apex:form>
            </apex:pageBlock>
        </apex:tab>
        <apex:tab id="caseContacts" label="Contacts">
            <apex:relatedList list="Case_Contacts__r"/>
        </apex:tab>
    </apex:tabPanel>
</apex:page>

There have been a few problems for the case comment related list. First, the list does not appear to work in an apex:relatedList tag like the other objects (case contacts is a custom junction object that allows for associating more then 1 contact to a case).

Some research on the internet showed that it is possible to get a list of case comments using the apex:pageBlockTable. I've been having trouble getting the actions to work.

URLFOR($Action.CaseComments.Edit, C.Id)

Fixes of this nature do not seem to work. I've been forced to hard code the URL's. This worked for the new button and the Edit links but the delete link does not work. I believe this is because it requires a confirmation token.

The questions I have are:

  1. Is it possible to use the global $Action variable to create links for the desired functions on case comments?
  2. If not, How do I generate a confirmation token for the delete action

EDIT:

I've continued doing research on the internet. One person recommended installing the Eclipse IDE and using the schema explorer to look up the relationship names of cases related list. This mostly worked but the following did not:

  • Case Comments (CaseComments)
  • Case History (Histories)
  • Attachments (Attachments)
  • Feed (Feeds)

Additionally, I have checked the SalesForce Reference for the Action variable: https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_variables_global_action_valid_values.htm

This seems to indicate that there are no actions for case comments or the various other related lists. If this is the case, I need to determine how to create confirmation tokens so that I can use the apex:pageBlockTable workaround.

Edit 2:

I found a post that hinted that the confirmation token was a hidden input element. While my research shows that this is only marginally true. It is not automatically placed on every page.

While playing around in the source code of various SF pages I found the following javascript:

chatter.getToolbox().setToken() = 'arbitrary token string'; 

This is only brought in if there is a feed on the record. I added a feed to my tabbed view using the following:

<apex:tab id="feedTab" label="Feed">
    <chatter:feed entityId="{!Case.Id}"/>
</apex:tab>

This made the following JavaScript valid:

chatter.getToolbox().token()

The last thing I need to do is work out a way to use that javascript to insert the token into the URL that is in the commandlink. Unfortunately, JavaScript is a weakness of mine.

Edit 3:

I was able to write some JS to use the token from the chatter toolbox; unfortunately, this was not the correct token. It varied ever so slightly from the confirmation token required to delete a case comment. Upon investigation, each individual comment is given a different confirmation token.

0
0

Looks like Case Comments related list cannot be referred directly. An alternate solution is to display it in a pageblocktable. See the suggested solution here

Putting this code should solve the issue

<apex:tab id="commentsTab" label="Comments">
    <apex:pageBlock>
        <apex:pageBlockTable value="{!case.casecomments}"var="c">
            <apex:column value="{!c.commentbody}"/>
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:tab>
2
  • 1
    I sincerely apologize, but I must point out that my code already has that within it. This solution poses certain problems. My post is about fixing those problems.
    – gNerb
    Oct 27 '15 at 19:42
  • ok. i understand, let me check again.
    – SF Ninja
    Oct 27 '15 at 19:47
0

Answer:

Apparently this works:

<apex:commandLink value="Del" action="{!URLFOR($Action.Account.Delete, c.Id, ['retURL'=Case.Id])}"/>

Best I gather, the delete action generates the confirmation token exclusively based on the ID of the object it is passed, regardless of whether or not the object is the same as the calling object. Because of this, we simply pass the ID of the case comment to the URLFOR($Action.Account.Delete, CaseComment.Id).

We need to also invoke the retURL parameter in order to make sure the user is not redirected to the account home page.

When I finish the rest of the page I'll post the entire thing here; since I've seen many people on the internet with the same issue.

EDIT:

It will not work with the new action because the URL for new objects contains the objects 3 letter prefix. For instance, a new case comment with go to:

my.salesforce.com/**00a**/e?retURL=%2F001%2Fo

but a new account will go to:

my.salesforce.com/**001**/e?retURL=%2F001%2Fo

As for the Edit action, I keep getting errors. Even though the edit URL is generic like the delete URL; the Edit function seems to require the proper object (cannot send a casecomment to the account object; substituting custom objects for the account object does not work either. Manually modifying URL's in the browser does work though).

Edit 2:

Visual Force:

<apex:page standardController="Case" extensions="CaseCommentController" >
    <apex:tabPanel switchType="Client" selectedTab="detailsTab">
        <apex:tab id="feedTab" label="Feed">
            <chatter:feed entityId="{!Case.Id}"/>
        </apex:tab>
        <apex:tab id="detailsTab" label="Details">
            <apex:detail relatedList="false"/>
        </apex:tab>
        <apex:tab id="commentsTab" label="Comments">
            <apex:pageBlock >
                <apex:form >
                    <div style="text-align:center;">
                        <apex:commandButton value="New" action="{!NewRecord}" />
                    </div>
                    <apex:pageBlockTable value="{!CaseCommentsSortedASC}" var="c">
                        <apex:column headerValue="Actions" width="50">
                            <apex:commandLink value="Edit" action="{!Edit}">
                                <apex:param assignTo="{!cId}" value="{!c.id}" name="cId" />
                            </apex:commandLink> &nbsp;
                            <apex:commandLink value="Del" action="{!URLFOR($Action.Account.Delete, c.Id, ['retURL'=Case.Id])}"/>
                        </apex:column>
                        <apex:column headerValue="Author" width="175">
                            {!c.createdby.Name} <br />
                            {!c.createdDate} <br />
                        </apex:column>
                        <apex:column headerValue="Comment">
                            {!c.commentbody}
                        </apex:column>
                    </apex:pageBlockTable>
                </apex:form>
            </apex:pageBlock>
        </apex:tab>
        <!--The following list is custom -->
        <apex:tab id="caseContactsTab" label="Contacts">
            <apex:relatedList list="Case_Contacts__r"/>
        </apex:tab>
        <!--End Custom List-->
        <apex:tab id="solutionsTab" label="Solutions">
            <apex:relatedList list="CaseSolutions"/>
        </apex:tab>
        <apex:tab id="openActivitiesTab" label="Open Activities">
            <apex:relatedList list="OpenActivities"/>
        </apex:tab>
        <apex:tab id="activityHistoryTab" label="Activity History">
            <apex:relatedList list="ActivityHistories"/>
        </apex:tab>
        <apex:tab id="approvalsTab" label="Approvals">
            <apex:relatedList list="ProcessSteps"/>
        </apex:tab>
        <apex:tab id="caseHistoryTab" label="Case History">
            <apex:pageBlock >
                <apex:form >
                    <apex:pageBlockTable value="{!Case.Histories}" var="h">
                        <apex:column headerValue="User" width="200">
                            {!h.createdby.Name}
                        </apex:column>
                        <apex:column headerValue="Date" width="200">
                            {!h.createdDate}
                        </apex:column>
                        <apex:column headerValue="Action">
                            {!If(h.field = "created", "", "Changed")} <b>{!h.field}</b> {!If(h.field = "created", "This", "From")} <b>{!h.oldValue}</b> {!If(h.field = "created", "Case", "To")} <b>{!h.newValue}</b>
                        </apex:column>
                    </apex:pageBlockTable>
                </apex:form>
            </apex:pageBlock>
        </apex:tab>
    </apex:tabPanel>
</apex:page>

Apex:

public class CaseCommentController {
    private final Case sourceCase;
    public List<CaseComment> CaseCommentsSortedASC{get; set;}
    public List<CaseComment> CaseCommentsSortedDESC{get; set;}
    public string cId {get;set;}

    public CaseCommentController (apexPages.StandardController stdCon) {
        this.sourceCase = (Case)stdCon.getRecord();
        this.CaseCommentsSortedASC = new List<CaseComment>();
        this.CaseCommentsSortedDESC = new List<CaseComment>();
        cId = '';
        sortCaseComments();
    }

    private void sortCaseComments() {
        for (Case c : [SELECT (SELECT CommentBody, CreatedById, CreatedBy.Name, CreatedDate, ParentId 
                       FROM CaseComments ORDER BY CreatedDate ASC) FROM Case WHERE Id = :sourceCase.Id]) {
            for (CaseComment cc : c.CaseComments) {
                this.CaseCommentsSortedASC.add(cc);
            }

            for (integer x = this.CaseCommentsSortedASC.Size()-1; x >= 0; x--) {
                this.CaseCommentsSortedDESC.add(this.CaseCommentsSortedASC[x]);
            }
        }
    }

    public PageReference Edit() {
        system.debug(cId + ' ' + sourceCase.Id);
        return new PageReference('/' + cId + '/e?parent_id=' + sourceCase.Id + '&retURL=' + sourceCase.Id);
    }

    public PageReference NewRecord() {
        system.debug(cId + ' ' + sourceCase.Id);
        return new PageReference('/00a/e?parent_id=' + sourceCase.Id + '&retURL=' + sourceCase.Id);
    }
}

I tried really hard to avoid creating a controller; however, the case comments were being sorted poorly (mostly when deleting/restoring deleted comments). The only fix was to code the controller. After I coded the controller I figured I'd add a few actions to create the Edit and New links.

Unfortunately, even with a controller, the Fix for the original issue remains the same. The only, relatively simple and direct, way to get a valid confirmation token is to use the delete action from a different object.

Next Steps:

The attachment list is not included but I imagine that will be very similar to the case comment list.

The Case history shows the ID of the owner when it is changed instead of the name. May consider expanding the controller to correct this. May also need to expand controller to sort case history.

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.