Repeating columns and rows in a table in your Word document is possible. It will require programming skills (APEX) but if you follow this tutorial and check your data with Butler Inspector you will be alright!
Thing to note: If you need only columns to repeat, that can be done via the Simple Column Repeater and will require no APEX
Example 1: #
Let’s say you want to display the Lead Source against all your Lead records in Salesforce. Each column will represent a Lead Source picklist value, and each row will include the Lead Name with a ‘Yes’ marked under the corresponding Lead Source it belongs to as shown below in the first screenshot. From the example, it’s evident that ‘Lead Source’ acts as a repeating column , while ‘Lead Name’ functions as a repeating row. So this example is the combination of both. This is possible with PDF Butler Complex Column repeater.
The second screenshot is the DocConfig Document with merge fields. You can download it here.
Let’s try to understand how to map our merge fields with the correct Data Sources and Data Source field. Before that create below Data Sources, DocConfig and also Actionable record for the DocConfig as shown below.
SOQL DataSource #
We need to have SOQL DataSource which fetches the column data from the Lead as shown below.
KEYVALUE Data Source #
Below is the KEYVALUE Data Source for row data. More information on KEYVALUE Data Source is found here
Main Word Document Doc Config #
Below is the Actionable record for above Doc Config.
Apex Class for Actionable Record #
Below is the Apex class required for Actionable record, which is referred in place of ‘Class’ field as shown above. This should run with Data Sources. So it implements cadmus_core.AbstractBeforeWithDataSourcesActionable. More information is found here.
This apex class sets the Data for each row against each column using the KEYVALUE Data Source created above.
global class MyActionable_LeadSourceColumnRepeater implements cadmus_core.AbstractBeforeWithDataSourcesActionable { global void execute(cadmus_core__Actionable__c actionable, Id docConfig, Id objectId, Map<String, Object> inputMap, Map<String, Object> dsMap, cadmus_core.ConvertController.ConvertDataModel cdm) { //get the DataSource from PDF Butler Object leadSourcesObj = dsMap.get('00D2p000000QL9s_a022p00000YNpp5'); //SOQL Lead DatSource id System.debug('leadSourcesObj: ' + leadSourcesObj); //get the data from the DataSource List<Map<String,Object>> leadSources = ((cadmus_core.ListWrapper)(leadSourcesObj)).data; System.debug('leadSources: ' + leadSources); //prepare the suffix for the columns in the rows Map<String,String> suffix = new Map<String,String>(); Integer counter = 0; for(Map<String,Object> leadSource : leadSources) { if(counter != 0) { suffix.put((String)leadSource.get('LeadSource'), '_' + counter); } else { suffix.put((String)leadSource.get('LeadSource'), ''); } counter++; } //Get Leads List<Map<String, String>> leadList = new List<Map<String, String>>(); //We use a SOQL in the class as an example that the data can come from a PDF Butler DataSource or can be retrieved in the Class // This also means that the data can come from a callout, a JSON file or ... List<Lead> leads = [SELECT Id, Name, LeadSource From Lead]; for(Lead ld : leads) { Map<String, String> leadItem = new Map<String, String>(); //Create the columns empty, we will overwrite the column in a few lines from now for(String val : suffix.values()) { leadItem.put('Item' + val, ''); } //Put the real data leadItem.put('Name', ld.Name); leadItem.put('Item' + suffix.get(ld.LeadSource), 'Yes'); //If you have more fields to handle, add them here. leadList.add(leadItem); } cadmus_core.ListWrapper dsLeads = new cadmus_core.ListWrapper(); dsLeads.data = leadList; //put back the data into the list of data to sent to PDF Butler dsMap.put('00D2p000000QL9s_a022p00000YNppA',dsLeads); //Id of Key Value DataSource Created for Table row } }
Open Doc Config PDF Builder and add Column Data Source(SOQL) with ct field which will hold the count.
Add row repeater KEYVALUE Data Source with Name and Item fields added manually. For every row, depending on the number of columns, row field should replicate. So create an Item field which will have the counter appended to it from apex class based on the number of columns.
PDF Butler Complex column repeater is going to create extra columns according to the column size as shown below. In the Data Source, first column will look for ‘Item’ and second column will look for ‘Item_1’ and so on. So, in the apex class make sure to append the counter to the ‘Item’ field.
Configtypes #
Create Complex Column Repeater Configtype that should be mapped to [[!COL_ITEM!]] merge field with SOQL Data Source which has column fields in the query
Column repeater will repeat LeadSource and ct(count) Data Source fields. So, create
- Child SINGLE Config type for LeadSource field that should map to [[!COL_ITEM!]] merge field
- Child SINGLE Config type for ct field that should map to [[!COUNT!]] merge field
Create TABLE_ROW Config type for the merge field [[!ROW_ITEM!]]. Row repeater will repeat Name and Item Data Source fields of Row repeaater KEYVALUE Data Source. So, create
- Child SINGLE Config type for ‘Name’ field that should map to [[!ROW_ITEM!]] merge field
- Child SINGLE_FOR_TABLE_COLUMN_REPEATER Config type for ‘Item’ field that should map to [[!ROW_COL_VALUE!]] merge field
Open any Lead record and edit the page to add PDF Butler Component and Doc Config Id to retrieve. Then Save. Generate the PDF.
Use a JSON as input for Complex Column Repeater: #
Find a demo below.
Thing to note: I would propose to use chatGPT to create a JSON parser that parses you data instead of writing it yourself!