How to Use an Apex-Defined Object with my Datatable Flow Component

How to Use an Apex-Defined Object with the Datatable Flow Component

Updated 1/23/21 to reference the v3 version of the Datatable that utilizes a Custom Property Editor.

I’ve updated my Datatable Lightning Web Component for Flow Screens to support a User Defined (also know as an Apex-Defined) object.

See my Flow and Process Builder List View with Batch Delete App for an example.

To work with an Apex-Defined object in your Flow, you need to create an Apex Descriptor Class for the object.


// Apex-Defined Variable Sample Descriptor Class
public with sharing class SampleClassDescriptor {

    // @AuraEnabled annotation exposes the methods to Lightning Components and Flows
    public String field1;

    public String field2;

    public Boolean field3;

    public Integer field4;    

    // Define the structure of the Apex-Defined Variable
    public SampleClassDescriptor(
            String field1,
            String field2,
            Boolean field3,
            Integer field4
    ) {
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
        this.field4 = field4;

    // Required no-argument constructor
    public SampleClassDescriptor() {}

In your Flow, you can create and use Apex-Defined record and record collection variables by referencing your Apex Class.

All of the fields in your variable will be available to use in the Flow.

In this sample Flow, I am setting field values in individual records as seen above.

I then add each record to the Apex-Defined record collection variable.

The Datatable component expects a serialized string of the object’s records and fields like the text seen here.


Since you can create Apex Flow Actions to work with your Apex-Defined object, I created an action that converts an Apex-Defined record collection to a serialized string that can be passed to the Datatable component. The action will also convert a serialized string back to a record collection. This can be useful in a Flow where you want to act on a collection of selected or edited records that get passed back to the Flow by the Datatable component.

Special Note: Even without an Apex-Defined Class, you can build a String in your Flow formatted as above and use that to populate a datatable.

You can use this code as a template for your own Apex actions designed to work with a Flow.


 *  Sample Apex Class Template to get data from a Flow, 
 *  Process the data, and Send data back to the Flow
 *  This example translates an Apex-Defined Variable 
 *  between a Collection of Object Records and a Seraialized String
 *  Eric Smith - May 2020

public with sharing class TranslateApexDefinedRecords {         // *** Apex Class Name ***

    // Attributes passed in from the Flow
    public class Requests {
        @InvocableVariable(label='Input Record String')
        public String inputString;

        @InvocableVariable(label='Input Record Collection')
        public List<SampleClassDescriptor> inputCollection;     // *** Apex-Defined Class Descriptor Name ***


    // Attributes passed back to the Flow
    public class Results {

        public String outputString;

        public List<SampleClassDescriptor> outputCollection;    // *** Apex-Defined Class Descriptor Name ***

    // Expose this Action to the Flow
    public static List<Results> translateADR(List<Requests> requestList) {

        // Instantiate the record collection
        List<SampleClassDescriptor> tcdList = new List<SampleClassDescriptor>();    // *** Apex-Defined Class Descriptor Name ***

        // Prepare the response to send back to the Flow
        Results response = new Results();
        List<Results> responseWrapper = new List<Results>();

        // Bulkify proccessing of multiple requests
        for (Requests req : requestList) {

            // Get Input Value(s)
            String inputString = req.inputString;
            tcdList = req.inputCollection;


            // Convert Serialized String to Record Collection
            List<SampleClassDescriptor> collectionOutput = new List<SampleClassDescriptor>();   // *** Apex-Defined Class Descriptor Name ***
            if (inputString != null && inputString.length() > 0) {
                collectionOutput = (List<SampleClassDescriptor>)System.JSON.deserialize(inputString, List<SampleClassDescriptor>.class);    // *** Apex-Defined Class Descriptor Name ***

            // Convert Record Collection to Serialized String
            String stringOutput = JSON.serialize(tcdList);


            // Set Output Values
            response.outputString = stringOutput;
            response.outputCollection = collectionOutput;

        // Return values back to the Flow
        return responseWrapper;


public with sharing class TranslateApexDefinedRecordsTest {

    static testMethod void test() {

        List<SampleClassDescriptor> inputList = new List<SampleClassDescriptor>();

        TranslateApexDefinedRecords.Requests testRequest = new TranslateApexDefinedRecords.Requests();

        testRequest.inputString = '[{"field1":"value1","field2":"value2"},{"field1":"value31","field2":"value4"}]';
        testRequest.inputCollection = inputList;

        List<TranslateApexDefinedRecords.Requests> testRequestList = new List<TranslateApexDefinedRecords.Requests>();

        List<TranslateApexDefinedRecords.Results> testResponseList = TranslateApexDefinedRecords.translateADR(testRequestList);
        system.debug('RESPONSE - '+testResponseList);
        system.assertEquals(testResponseList[0].outputCollection.size(), 2);


When you configure the attributes for the Datatable in your Flow, you need to be aware of these settings:

  1. Start by checking Input data is Apex-Defined in the Advanced section
  2. In the Data Source section, enter your Datatable Record String
  3. Also in the Data Source section, enter a Datatable Record String for any Pre-Selected Rows
  4. There is no Column Wizard so you will have to list your Column Field names and other attributes manually.
  5. For Currency, Number and Percent fields the Column Scales attribute lets you specify the number of places to display after the decimal point. The default is 0.
  6. When you are using an SObject collection, the Datatable component gets information about all of the fields from the system. For a User Defined object, you need to specify the Column Type of data for each field. This can be left blank if all of the columns are text fields.
  7. You are required to provide the name of the datatable’s Key Field. All of the values in this field need to be unique in order for the datatable to function correctly.

There are separate output parameters for Selected and Edited User Defined objects as well.

The (User Defined) outputs will be serialized record strings rather than SObject collections. Be sure to reference the correct ones based on how you assigned the True or False value for the Input data is Apex-Defined attribute.

Get the Sample Flow and Source Code here: