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
adrisseladrissel 

Custom button validation and passing selected records

I have placed a custom button on a Case List view.  The button, when clicked, needs to validate whether any case records were actually selected.  That part is done simply with a Javascript OnClick button with the following code:

{!REQUIRESCRIPT ("/soap/ajax/13.0/connection.js")} 

var selected = {!GETRECORDIDS($ObjectType.Case)}; 

if (selected[0] == null) { 

    alert("Please select at least one Case.")
} 

else {

     window.location = 'apex/MyPage';
}

The problem is that when validation passes (i.e. it goes to the MyPage visualforce page) the selected records aren't passed along.  Here is my VF page thus far:

<apex:page standardController="Case" recordSetVar="cases">
   <apex:form >
       <apex:pageBlock title="MyPage" mode="edit">
            <apex:pageBlockButtons >
                <apex:commandButton action="{!save}" value="MyButton"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="Information" columns="2">
                <apex:inputCheckBox value="{!case.test__c}" selected="true" required="true"/>
                <apex:pageBlockSectionItem />
                <apex:inputField value="{!case.test2__c}" showDatePicker="true" required="true"/>
                <apex:inputField value="{!case.test3__c}" showDatePicker="true" required="true"/>
            </apex:pageBlockSection>
            <apex:pageBlockSection title="Selected Cases">
                <apex:pageBlockTable value="{!selected}" var="case">
                    <apex:column value="{!case.casenumber}"/>
                    <apex:column value="{!case.subject}"/>
                    <apex:column value="{!case.status}"/>
                </apex:pageBlockTable>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>   
</apex:page>
The goal is to have the custom button on the List view validate whether records are checked, then when validation passes have those records displayed in the block table on the VF page.  I can get one or the other to work, but not both at the same time.  If I change the button to go directly to the VF page, the selected records appear perfectly, but no validation occurs (i.e. it allows redirect when no records are selected).  If I have the button set to the Javascript code it validates the records but doesn't display the selected records on the VF page.

I have searched the internet for hours on everything I could think of and couldn't find anything to help me.  

Can anyone out there offer a solution?

THANKS!!
Best Answer chosen by adrissel
vmanumachu1.393650924860069E12vmanumachu1.393650924860069E12
Here you go. It works.

VF:

<apex:page standardController="Case" recordSetVar="cases" extensions="apxCaseStanSetController">
   <apex:form >
       <apex:pageBlock title="MyPage" mode="edit">
            <apex:pageBlockButtons >
                <apex:commandButton action="{!doSave}" value="MyButton"/>
            </apex:pageBlockButtons>
             <apex:pageBlockSection title="Case Information" columns="2">
                <apex:inputField value="{!NewCase.Value2__c}" showDatePicker="true" required="true"/>
                <apex:inputField value="{!NewCase.Value3__c}" showDatePicker="true" required="true"/>
            </apex:pageBlockSection>
            <apex:pageBlockSection title="Selected Cases">
                <apex:pageBlockTable value="{!cases}" var="case">
                    <apex:column value="{!case.casenumber}"/>
                    <apex:column value="{!case.subject}"/>
                    <apex:column value="{!case.status}"/>
                </apex:pageBlockTable>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>  
</apex:page>


Controller:

public with sharing class apxCaseStanSetController {
ApexPages.StandardSetController setCon;
List<string> strIds = new List<string>();
List<Case> lstcase = new List<Case>();
public case c;
public Case getNewCase()
{
  if(c==null)c= new case();
  return c;
}
public apxCaseStanSetController (Apexpages.Standardsetcontroller cont)
{
setCon = cont;
strIds = ApexPages.currentPage().getParameters().get('recs').split(',',-2);
}
public List<Case> getCases()
{
lstcase = [select Subject,CaseNumber, Status,Id from Case where id IN: strIds ];
return lstcase;
}
public Pagereference doSave()
{
List<Case> updatecase = new List<Case>();
for(Case cse : lstCase)
{
  cse.Value2__c = c.Value2__c;
  cse.Value3__c = c.Value3__c;
  updatecase.add(cse);
}
update updatecase;

return new Pagereference('/'+Case.getSObjectType().getDescribe().getKeyPrefix()+'/o');
}
}

All Answers

adrisseladrissel
Thanks for the quick reply, Anoop.  However, those two links again seem like a "one way or the other" type situation.  I have my mass update working, no problem.  That is one option I have.  Then I can change the button to a Javascript one and perform validation, no problem.  

The problem is that I cannot do both at the same time.  Ideally I would like the button to be a Javascript OnClick button (as in your second link above) to perform the validation, but then after validation passes based on the button code the selected records are passed to a VF page for displaying.  Can this not be done?

Am I missing something obvious here? :(
vmanumachu1.393650924860069E12vmanumachu1.393650924860069E12
Hi,

I dont think you can do both at the same time. The current API doesnt support this since the controller reference is lost. But, here is a work around. You have to write an extension to the standard controller.
Please mark as best anwser if it works for you. It helps others.

Below is the code:

Button Code:

{!REQUIRESCRIPT("/soap/ajax/19.0/connection.js")}
var url = parent.location.href;
var records = {!GETRECORDIDS($ObjectType.Case)};
var updateRecords = [];

if (records[0] == null) {
alert("Please select at least one record to update.");
} else {

window.location = 'apex/vfcasepage?recs='+records.join(',');
}

VF Code:

<apex:page standardController="Case" recordSetVar="cases" extensions="apxCaseStanSetController">
   <apex:form >
       <apex:pageBlock title="MyPage" mode="edit">
            <apex:pageBlockButtons >
                <apex:commandButton action="{!save}" value="MyButton"/>
            </apex:pageBlockButtons>
           
            <apex:pageBlockSection title="Selected Cases">
                <apex:pageBlockTable value="{!cases}" var="case">
                    <apex:column value="{!case.casenumber}"/>
                    <apex:column value="{!case.subject}"/>
                    <apex:column value="{!case.status}"/>
                </apex:pageBlockTable>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>  
</apex:page>

Controller:

public with sharing class apxCaseStanSetController {
ApexPages.StandardSetController setCon;
List<string> strIds = new List<string>();
public apxCaseStanSetController (Apexpages.Standardsetcontroller cont)
{
setCon = cont;
strIds = ApexPages.currentPage().getParameters().get('recs').split(',',-2);
}
public List<Case> getCases()
{
return [select Subject,CaseNumber, Status from Case where id IN: strIds ];
}
}

Please mark as best anwser if it works for you. It helps others.

adrisseladrissel

Amazing!  Works perfectly!  Thanks!!

One follow-up question if you don't mind.  When I click to save the records on the VF Page the redirect is to the Home tab.  Any way to go back to the Case List View page?

Also, is the "?recs='+records.join(',')" URL extension in some Apex documentation somewhere?

Thanks again!

adrisseladrissel
Had to remove the best answer...sorry :(  After further testing it appears that the apex is no longer updating the case fields.  When I stop  using the JavaScript button, and make it a VF page button, it works fine.  The records are passed fine, it seems, but for some reason the case field values aren't updating.  

Thoughts?
vmanumachu1.393650924860069E12vmanumachu1.393650924860069E12
I thought your question was how to get the selected recs shown in VF page..anyways, if you need to update the selected recs, you need handle the updates in Apex. Post your VF and Apex code, i can you help you out.
adrisseladrissel

Cool, thanks!  Here is the custom button code:

{!REQUIRESCRIPT("/soap/ajax/19.0/connection.js")}

var url = parent.location.href;

var records = {!GETRECORDIDS($ObjectType.Case)};

var updateRecords = [];

if (records[0] == null) {

alert("Please select at least one Case to update.");
} 

else {

window.location = 'apex/MyVFPage?recs='+records.join(',');
}
This works excellent, by the way, for pulling the records!

Here is my controller extension:
public with sharing class GetSelectedCases {

    ApexPages.StandardSetController setCon;
    
    List<string> caseIds = new List<string>();
    
    public GetSelectedCases (Apexpages.StandardSetController controller) {
    
        setCon = controller;
    
        caseIds = ApexPages.currentPage().getParameters().get('recs').split(',',-2);
    }
    
    public List<Case> getSelected() {
    
        return [SELECT Subject,CaseNumber,Status FROM Case WHERE Id IN: caseIds];
    }
}

Both of those working together work perfectly to display the records on the VF page.  Love it!

Here is the VF page:

<apex:page standardController="Case" recordSetVar="Cases" extensions="GetSelectedCases">
   <apex:form >
       <apex:pageBlock title="My Title" mode="edit">
            <apex:pageBlockButtons >
                <apex:commandButton action="{!save}" value="Save"/>
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="Case Information" columns="2">
                <apex:inputCheckBox value="{!case.value1__c}" selected="true" required="true"/>
                <apex:pageBlockSectionItem />
                <apex:inputField value="{!case.value2__c" showDatePicker="true" required="true"/>
                <apex:inputField value="{!case.value3__c}" showDatePicker="true" required="true"/>
            </apex:pageBlockSection>
            <apex:pageBlockSection title="Selected Cases">
                <apex:pageBlockTable value="{!selected}" var="case">
                    <apex:column value="{!case.casenumber}"/>
                    <apex:column value="{!case.subject}"/>
                    <apex:column value="{!case.status}"/>
                </apex:pageBlockTable>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>    
</apex:page>


Here's where the issue and different behavior happens.  This is what I notice:

(1) If I don't use the Javascript button, but instead just make it a VF page button that directs to that VF page, the field updates work perfectly!

(2) If I use the Javascript button, the records are displayed properly, but the two following things don't function properly:
--> a) The Fields don't update in the selected case records
--> b) The redirect page after submission isn't the case view list, it is the home tab (unlike the behavior without the Javascript button)

Am I missing something that needs to be there to update the field data?

Thanks again!!

vmanumachu1.393650924860069E12vmanumachu1.393650924860069E12
So, you want to update values from the case.value2__c & case.value3__c for the selected recs? 
vmanumachu1.393650924860069E12vmanumachu1.393650924860069E12
Here you go. It works.

VF:

<apex:page standardController="Case" recordSetVar="cases" extensions="apxCaseStanSetController">
   <apex:form >
       <apex:pageBlock title="MyPage" mode="edit">
            <apex:pageBlockButtons >
                <apex:commandButton action="{!doSave}" value="MyButton"/>
            </apex:pageBlockButtons>
             <apex:pageBlockSection title="Case Information" columns="2">
                <apex:inputField value="{!NewCase.Value2__c}" showDatePicker="true" required="true"/>
                <apex:inputField value="{!NewCase.Value3__c}" showDatePicker="true" required="true"/>
            </apex:pageBlockSection>
            <apex:pageBlockSection title="Selected Cases">
                <apex:pageBlockTable value="{!cases}" var="case">
                    <apex:column value="{!case.casenumber}"/>
                    <apex:column value="{!case.subject}"/>
                    <apex:column value="{!case.status}"/>
                </apex:pageBlockTable>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>  
</apex:page>


Controller:

public with sharing class apxCaseStanSetController {
ApexPages.StandardSetController setCon;
List<string> strIds = new List<string>();
List<Case> lstcase = new List<Case>();
public case c;
public Case getNewCase()
{
  if(c==null)c= new case();
  return c;
}
public apxCaseStanSetController (Apexpages.Standardsetcontroller cont)
{
setCon = cont;
strIds = ApexPages.currentPage().getParameters().get('recs').split(',',-2);
}
public List<Case> getCases()
{
lstcase = [select Subject,CaseNumber, Status,Id from Case where id IN: strIds ];
return lstcase;
}
public Pagereference doSave()
{
List<Case> updatecase = new List<Case>();
for(Case cse : lstCase)
{
  cse.Value2__c = c.Value2__c;
  cse.Value3__c = c.Value3__c;
  updatecase.add(cse);
}
update updatecase;

return new Pagereference('/'+Case.getSObjectType().getDescribe().getKeyPrefix()+'/o');
}
}
This was selected as the best answer
adrisseladrissel
Excellent work!!!  Thank you very much.  Tested, works, amazing!  
Susheel Reddy BSusheel Reddy B

Hi Adrissel,

Did you get any solution for this test class. I have similar requiremnet and unbale to write test class. Please share the code if you have.
Thanks in advance.

Thanks,
Susheel Reddy
adrisseladrissel
Sure.  Here is the code that ended up working for me:

CONTROLLER: 
public with sharing class OutOfOffice {

    ApexPages.StandardSetController setCon;
    
    List<string> caseIds = new List<string>();
    
    List<Case> caseList = new List<Case>();
    
    public Case c;

    public Case getNewCase() {
            
        c = new Case();
        
        return c;
    }
    
    public OutOfOffice (Apexpages.StandardSetController controller) {
    
        setCon = controller;
    
        caseIds = ApexPages.currentPage().getParameters().get('recs').split(',',-2);
    }
    
    public List<Case> getSelected() {
    
        caseList = [SELECT Subject,CaseNumber,Status FROM Case WHERE Id IN: caseIds];
    
        return caseList;
    }
    
    public Pagereference updateCases(){
    
        List<Case> updatedCases = new List<Case>();
        
        for(Case cse : caseList){
        
            cse.Out_Of_Office_Start__c = c.Out_Of_Office_Start__c;
            
            cse.Out_Of_Office_End__c = c.Out_Of_Office_End__c;
            
            cse.Out_Of_Office__c = c.Out_Of_Office__c;
            
            updatedCases.add(cse);
        }
        
        update updatedCases;

        return new Pagereference('/'+Case.getSObjectType().getDescribe().getKeyPrefix()+'?fcf='+ApexPages.currentPage().getParameters().get('retUrl'));
    }
    
    public Pagereference cancelUpdate(){

        return new Pagereference('/'+Case.getSObjectType().getDescribe().getKeyPrefix()+'?fcf='+ApexPages.currentPage().getParameters().get('retUrl'));
    }
}

VF Page:
<apex:page standardController="Case" recordSetVar="Cases" extensions="OutOfOffice">
    <head>
        <title>Enable Out Of Office</title>
    <script> 
    
        function outOfOffice(cancel) {
        
            var ooo = document.getElementById('{!$Component.form.block.section.ooo}').value;
            var start = document.getElementById('{!$Component.form.block.section.start}').value;
            var end = document.getElementById('{!$Component.form.block.section.end}').value;
            var d = new Date();
            var startDate = Number(new Date(start));
            var endDate = Number(new Date(end));
            var time = Number(new Date((d.getMonth() + 1) + "/" + d.getDate() + "/" + d.getFullYear()));
            
            if (cancel == 1) {
            
                cancelFunction();
            }
            
            else {

                if (ooo != null && ((start == '' || start == null) || (end == '' || end == null))) {
    
                    alert("Please enter both a Start Date and an End Date.");
                }
    
                else if (endDate < startDate) {
    
                    alert("The End Date cannot be earlier than the Start Date.  Please enter a valid End Date.");
                }
    
                else if (startDate < time) {
    
                    alert("The Start Date cannot be a date in the past.  Please enter a valid Start Date.");
                }
    
                else {
    
                    alert("Out Of Office has been enabled for the Selected Cases.")
    
                    updateFunction();
                }
            }
        }
    </script>
    </head>
    <apex:form id="form" >
        <apex:pageBlock id="block" title="Enable Out Of Office Replies" mode="edit">
            <apex:pageBlockSection id="section" title="Out Of Office Information" columns="2">
                <apex:inputCheckBox id="ooo" value="{!NewCase.Out_Of_Office__c}" selected="true" required="true"/>
                <apex:pageBlockSectionItem />
                <apex:inputField id="start" value="{!NewCase.Out_Of_Office_Start__c}" showDatePicker="true"/>
                <apex:inputField id="end" value="{!NewCase.Out_Of_Office_End__c}" showDatePicker="true"/>
            </apex:pageBlockSection>
            <apex:pageBlockSection title="Selected Cases">
                <apex:pageBlockTable value="{!selected}" var="case">
                <apex:column value="{!case.casenumber}"/>
                <apex:column value="{!case.subject}"/>
                <apex:column value="{!case.status}"/>
                </apex:pageBlockTable>
            </apex:pageBlockSection>
        </apex:pageBlock>
    <center><input type="button" value="Enable Out Of Office" onclick="outOfOffice();" /><input type="button" value="Cancel" onclick="outOfOffice(1);" /></center>
    <apex:actionFunction name="updateFunction" action="{!updateCases}"/>
    <apex:actionFunction name="cancelFunction" action="{!cancelUpdate}"/>
    </apex:form>
</apex:page>

CUSTOM BUTTONS:

Enable:
{!REQUIRESCRIPT("/soap/ajax/19.0/connection.js")}

var url = parent.location.href.split('fcf=');

var retUrl = url[1];

var records = {!GETRECORDIDS($ObjectType.Case)};

var updateRecords = [];

if (records[0] == null) {

alert("Please select at least one Case to update.");
} 

else {

window.location = 'apex/Enable_Out_Of_Office?recs='+records.join(',')+'&retUrl='
+retUrl;
}

Disable:
 
{!REQUIRESCRIPT ("/soap/ajax/13.0/connection.js")} 

var records = {!GETRECORDIDS($ObjectType.Case)}; 

var newRecords = []; 

if (records[0] == null) { 

alert("Please select at least one Case to update.")
} 

else {

for (var a = 0; a < records.length; a++) { 

var c = new sforce.SObject("Case"); 

c.id = records[a]; 

c.Out_Of_Office__c = false;

c.Out_Of_Office_Start__c = null;

c.Out_Of_Office_End__c = null;

newRecords.push(c);
} 

result = sforce.connection.update(newRecords);

alert("Out Of Office replies have been disabled for all selected Cases.");

window.location.reload(); 
}

Does that provide you with all the information you need?  Let me know if you have questions!
Susheel Reddy BSusheel Reddy B
Hi Adrissel,

Thanks for posting you code. Even I have written similar code. I need help with test class for this code.

Thanks,
Susheel Reddy
adrisseladrissel
Okay, gotcha.  This gives my controller 100% code coverage:
 
@isTest
private class OutOfOfficeTest{

    private static testmethod void testOutOfOffice() {
      
        Profile pro = [SELECT Id FROM Profile WHERE Name = 'System Administrator' LIMIT 1];
    
        PageReference pageRef = Page.Enable_Out_Of_Office;
        
        List<Case> caseIds = new List<Case>();
        
        
        // CREATE TEST USER FOR TESTING
        
        User u = new User(
            alias = 'u2', 
            email = 'test@test.com',
            emailencodingkey = 'UTF-8',
            FirstName = 'test',
            lastname='U',
            languagelocalekey = 'en_US',
            localesidkey = 'en_US',
            profileid = pro.Id,
            timezonesidkey = 'America/Los_Angeles',
            CommunityNickname = 'u2',
            isActive = true,
            username = 'testSciquest@test.com'
        );
        
        insert u;
    
        // CREATE AND INSERT TEST CONTACT
        
        Contact con = new Contact (LastName = 'Smith', FirstName = 'Joe', Email = 'joesmith@test.com');
        
        insert con;
        
        
        // CREATE START AND END DATES
        
        Date startDate = date.today();
        
        Date endDate = startDate.addDays(1);
        
        System.RunAs(u){
    
        
            // CREATE AND INSERT NEW CASES
            
            Case c1 = new Case(
            
                Subject = 'Test Case 1',
                Status = 'Initial',
                Out_Of_Office__c = true,
                Out_Of_Office_Start__c = startDate,
                Out_Of_Office_End__c = endDate,
                ContactId = con.Id
            );
            
            insert c1;
            
            caseIds.add(c1);
            
            Case c2 = new Case(
            
                OwnerId = '005a000000B3pqh',
                Subject = 'Test Case 2',
                Status = 'Initial',
                Out_Of_Office__c = true,
                Out_Of_Office_Start__c = startDate,
                Out_Of_Office_End__c = startDate,
                ContactId = con.Id
            );
            
            insert c2;
            
            caseIds.add(c2);
    
        
            // SET PAGE REFERENCE URL            
            
            pageRef.getParameters().put('recs',c1.Id+','+c2.id);
        
            Test.setCurrentPage(pageRef);
            
            OutOfOffice ooo = new OutOfOffice(new ApexPages.StandardSetController(caseIds));  
            
            ooo.getNewCase();
            ooo.getSelected();
            ooo.updateCases();
            ooo.cancelUpdate();
        
            
            // CREATE AND INSERT NEW EMAIL
            
            EmailMessage em = new EmailMessage(
                FromAddress = 'test@example.com',
                Incoming = true,
                ToAddress = 'test@gmail.com',
                Subject = 'Test email',
                TextBody = 'Hello',
                ParentId = c1.Id
            );
            
            insert em;
            
        
            // CREATE AND INSERT TEST CASE COMMENTS
            
            CaseComment com1 = new CaseComment (
            
                CommentBody = 'test',
                ParentId = c1.Id,
                IsPublished = true
            ); 
            
            insert com1;
            
            CaseComment com2 = new CaseComment (
            
                CommentBody = 'test',
                ParentId = c2.Id,
                IsPublished = true
            ); 
            
            insert com2;
        }
    }
}

That help?
smitha vikramsmitha vikram
So the request I have is to create a custom button on opportunity that pops a window allowing the user to add a comment
: That comment must be appended with today date and should be added to comment section
 Next time another comment is added the previous comment should be added to a description filedSo on so forth
[4:42 AM, 8/9/2019] S: Where comment and description will be read only fields on the page
[4:42 AM, 8/9/2019] S: Comment is Rich text field
 
o i have my apex class ...
public with sharing class AddCommentbuttonOpportunity  {
  
public Opportunity getComments{get;set;}

 public AddCommentbuttonOpportunity(Apexpages.StandardController  controller){
   
   List<String> fields= new List<String> {'Comments_Next_Steps__c'};
    
controller.addFields(fields);

this.getComments=(Opportunity)controller.getRecord();

if(getComments.Comments_Next_Steps__c!=null) {

getComments.Comments_Next_Steps__c = System.today() + ' ' + getComments.Comments_Next_Steps__c;
string temp= getComments.Description;

if(temp==null && String.isBlank(temp)){
getComments.Description=  getComments.Comments_Next_Steps__c;
}else If(temp!=null && String.isNotBlank(temp)){
 getComments.Description=  getComments.Comments_Next_Steps__c +'/n' +temp;
 }
 }
 }

 public PageReference save()
      
      {

 insert getComments;
    return new PageReference('/'+getComments.id);



 }
 }

This is my VF page

<apex:page sidebar="false" standardController="Opportunity" extensions="AddCommentbuttonOpportunity">
    <apex:form >
     <apex:pageBlock title="Add a New Comment">

        <apex:pageBlockSection >

           <apex:inputfield value="{! Opportunity.Comments_Next_Steps__c}" /> <br/>

        </apex:pageBlockSection>

    <apex:pageBlockButtons >
   <apex:commandButton action="{!save}" value="Save"/>
    </apex:pageBlockButtons>
    </apex:pageBlock>

    </apex:form>

</apex:page>

but when i enter value and click save i am getting error '
what am i  missing