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.
We need to have one more DataSource which fetches the row 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 #
Create below 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 DataSource id for column data like LeadSource and count in this example //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++; } Object rows_object = dsMap.get('00D2p000000QL9s_a022p00000PAp87');//data source for row data like Name,LeadSource in this example List<Map<String,Object>> rowsData = ((cadmus_core.ListWrapper)(rows_object)).data; system.debug('rowsData'+rowsData); List<Map<String, String>> leadList = new List<Map<String, String>>(); for(Map<String,Object> rw : rowsData) { Map<String, String> rowItem = new Map<String, String>(); //Create the columns empty, we will overwrite the column in a few lines from now for(String val : suffix.values()) { rowItem.put('Item' + val, ''); } //Put the real data rowItem.put('Name', String.valueOf(rw.get('Name'))); rowItem.put('Item'+ suffix.get(String.valueOf(rw.get('LeadSource'))), 'Yes'); //If you have more fields to handle, add them here. leadList.add(rowItem); } 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 make sure to add all the 3 data sources in to the DocConfig.
When adding Column Data Source(SOQL), add ‘ct’ (ct is the name which you have given for count() in your column data source soql query) field manually as shown below.
When adding KEYALUE Data Source, add Name(api name of field which will hold lead name) and Item(you can give any name instead of ‘Item’ , but make sure to give same name in the actionable apex class mentioned above) fields added manually as shown in below screenshot. As this is the KEYVALUE data source, data will be set to this data source in the actionable apex class using these field names
For every row, depending on the number of columns, ROW_COL_VALUE field should replicate.
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 ‘Item’ field which we should map to the ROW_COL_VALUE will have the counter appended to it from actionable apex class based on the number of columns.
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 repeater 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!