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
JskinJskin 

Creating a 2nd "Select all" tickbox on a VF Page

We have an application we use to manage events and the attendees(enrolments).  I have created a simple VF page which displays a list of the attendees for an event and allows you to select whether to print or email a certificate for them.  

 

I would like to develop this further in 2 ways:

 

1. have a tickbox at the top to "select all" the attendees for either printing or email the certificate.  I want to stick with the 2 columns as it lets me keep to my simple workflows instead of further code (I'm not a developer)

 

2.from the selected attendees generate a PDF with all the selected attendee certificates in one pdf document (I currently can only review one at a time.

 

 

For the first part:

 

I have managed to get one "select all" box working from research on this site but am unsure how to do a second - anything I have tried just selects the same fields.  Code is as follows:

 

<apex:page standardController="Enrollment__c" recordSetVar="Enrollments" sidebar="false">
    <apex:sectionHeader title="Email/Print Certificates" />
        <apex:form >
          <apex:pageBlock >
             <apex:pageMessages />
                <apex:pageBlockButtons >
                    <apex:commandButton value="Save/Send Email" action="{!save}" />
                    <apex:commandButton value="Cancel" action="{!cancel}" />
                </apex:pageBlockButtons>
             <apex:pageBlockSection title="Selected Enrollments" columns="1" collapsible="False">
                    <apex:pageBlockTable value="{!selected}" var="Enrollment">
                       <apex:column value="{!Enrollment.name}"/>
                       <apex:column value="{!Enrollment.Delegate_name__c}"/>
                       <apex:column value="{!Enrollment.Booking_status__c}"/>
                       <apex:column value="{!Enrollment.Invoice_status__c}"/>
                       <apex:column value="{!Enrollment.Exam_results__c}"/>
                       <apex:column value="{!Enrollment.Exam_percentage__c}"/>
                       <apex:column value="{!Enrollment.Hold_Certificate__c}"/>
                       <apex:column value="{!Enrollment.Certificate_status__c}"/>
                       <apex:column headerValue="Review PDF/Open to print">
                       <apex:outputlink target="_blank" value="https://cs7.salesforce.com/apex/ReviewPDFcert?id={!Enrollment.id}">review pdf</apex:outputlink> <br/>
                                              
                        <apex:column >
                           <apex:facet name="header">
                                <apex:outputPanel >
                                    <apex:outputLabel value="Cert Printed?" for="Select_All_Print"/>
                                    <apex:inputCheckbox onclick="checkAll(this)" id="Select_All_Print"/>
                                </apex:outputPanel>
                           </apex:facet>
                          <apex:inputField id="Selectd_Print" value="{!Enrollment.Certificate_Printed__c}"/>
                        </apex:column>
                                             
                       <apex:column headerValue="Select PDF Certificates to Email"><apex:inputField value="{!Enrollment.Email_PDF_Certificate__c}"/></apex:column>
                   </apex:pageBlockTable>
                                                                      
              </apex:pageBlockSection>
          <apex:outputlink target="_blank" value="https://cs7.salesforce.com/apex/ReviewPDFcertList?id={!selected}">Review all selected Certificates</apex:outputlink>
                                           
        </apex:pageBlock>
    </apex:form>
   
    <script type="text/javascript">
      function checkAll(cb)
        {
            var inputElem = document.getElementsByTagName("input");          
            for(var i=0; i<inputElem.length; i++)
            {   
                 if(inputElem[i].id.indexOf("Selectd_Print")!=-1)                         
                inputElem[i].checked = cb.checked;
            }
        }
</script>
        
</apex:page>

 

 

Then my second issue is really what variable or id I can use to generate all the PDFs for the individual I have been using

 

..../apex/ReviewPDFcert?id={!Enrollment.id}

 

My VF page "ReveiwPDFcert" picks up the enrolment and creates a simple certificate.    I am not sure what to replace the   id={enrollment.id} with or on the pdf page,    <apex:page renderAs="pdf" standardController="Enrollment__c" showHeader="false" pageStyle="all">, what to use as the variable (I know I want it to show all of the attendees who have Enrollment.Certificate_Printed__c selected as per above).

 

Any help offered on this would be gratefully received - custom controllers and extensions are still beyond me.  Many Thanks.

 

 

 

 

 

joshbirkjoshbirk

So the solution is probably a little more complicated than it seems, mostly because what you need is to filter through the data set and hand the results off to a new interface (the VF page which will render the PDF).  I've got a simplified example which will hopefully help.

 

Visualforce/Apex supports what could be called a "wizard" flow, where you can maintain the state between two (or more) Visualforce pages.  Here I've got one Visualforce page which shows a list of contacts and a corresponding set of checkboxes:

 

<apex:page controller="WizardExample" >
 
<apex:form >
<apex:commandButton action="{!previewPDF}" value="Preview PDF"  />
    <input type="checkbox" onclick="checkAll(this,'Selectd_Print')" />Print All /
    <input type="checkbox" onclick="checkAll(this,'Selectd_Email')" />Email All
    
<script type="text/javascript">
      function checkAll(cb,filter)
        {
            var inputElem = document.getElementsByTagName("input");          
            for(var i=0; i<inputElem.length; i++)
            {   
                if(inputElem[i].id.indexOf(filter)!=-1)                         
                inputElem[i].checked = cb.checked;
            }
        }
</script>
<apex:dataTable value="{!points}" var="point">
    <apex:column ><apex:facet name="header">Name</apex:facet><apex:outputField value="{!point.contactData.Name}" /></apex:column>
    <apex:column ><apex:facet name="header">Print</apex:facet><apex:inputCheckbox id="Selectd_Print" value="{!point.isPrint}"/></apex:column>
    <apex:column ><apex:facet name="header">Email</apex:facet><apex:inputCheckbox id="Selectd_Email" value="{!point.isEmail}"/></apex:column>
</apex:dataTable>
</apex:form>
            
    
</apex:page>

 

Now, you might notice I'm not referencing the Contact records directly.  This is because in my case, Contacts don't have a datapoint to record if it is going to be emailed or printed.  You could add these as custom fields, but because they're so transient we don't entirely need to - instead I'm going to use another Apex class to describe the data I need;

 

public class DataPoint {

    public Boolean isPrint {get; set;}
    public Boolean isEmail {get; set;}
    public Contact contactData {get; set;}
    
    public DataPoint(Contact c) {
            contactData = c;
    }
}

 So this way I can wrap the Contacts with the data I'll need later.  It's also convenient because this is bound directly to my datatable and I don't need to do anything else to base logic off my checkboxes.

 

Here's my controller:

 

public class WizardExample {

    public transient List<Contact> contacts {get; set;}
    public List<DataPoint> points {get; set;}
    
    public List<Contact> contactsToPrint {get; set;}
    public List<Contact> contactsToEmail {get; set;}
    
    public String contentType {get; set;}
    
    public WizardExample() {
        contentType = 'html';
        contacts = [SELECT ID, Name from Contact LIMIT 100];
        points = new List<DataPoint>();
        for(Contact c : contacts) {
            points.add(new DataPoint(c));
        }    
    }
    
    public PageReference previewPDF() {
        contactsToPrint = new List<Contact>();
        contactsToEmail = new List<Contact>();
        for(DataPoint point : points) {
            if(point.isPrint) { 
                contactsToPrint.add(point.contactData); 
            }
            if(point.isEmail) { 
                contactsToEmail.add(point.contactData); 
            }
        }
        points.clear();
        return Page.StepTwo;
    }
    
    public PageReference showPDF() {
        contentType = 'PDF';
        return Page.StepTwo;
    }
    
}

 I'll put the whole set of contacts into the main array, but then I create the DataPoint objects based on them, and that array is what the datatable will see.  

 

When the commandbutton is hit in StepOne, previewPDF will be called and split the records into the two new arrays.  If we don't do any other kind of redirect, "return Page.StepTwo" will return the StepTwo Visualforce page, but with data we were handling already.

 

Now the PDF is a two step process here because the PDF renderer gets a little excited and isn't completely aware of the new state of the page.  Adding an intermediary step allows it to attempt to render correctly.  With contentType variable, I can flip the preview to the actual PDF.

 

You might want a simpler intermediary page that goes to your PDF generation without displaying all the records twice.

 

There's a couple ways to skin this particular cat, but hopefully that will give you a baseline of code to work with.

 

Are looking to use Apex to email the certs out as well?

 

JskinJskin

Hi Joshbirk,

 

Thanks for the help offered above and sorry its taken so long for me to respond.  Unfortunately the code was a bit above my head still and took a while for me to try it out.

 

I finally found a different solution: 

 

The attendees all have a record stored on the custom Enrolment object which is in Master Detail relationship with another custom object called Training Event (the event is the master).

 

I created a VF page which opens as a pdf from the Training event and used an apex:repeat to iterate over each enrolment/delegate so a pdf with all the certificates within it is produced.

 

 

 

<apex:page renderAs="pdf" standardController="Training_Event__c" showHeader="false" pageStyle="all">
<head>
<style type="text/css" media="print">
body{font-family: Arial Unicode MS; font-size: 10pt;}
 
<apex:repeat value="{!Training_Event__c.Enrollments__r}" var="enr">

<!------code for displaying text on certificate for the enrolment certificate----->

<!------added in a table to produce a page break after each delegate/enrolment----->

<table height="0.1">
  <tr><td> <div style="page-break-after:always"></div></td></tr>
</table>
                              
 
 </apex:repeat>
 
</body>
</apex:page>