Lightning Web Components – Custom Property Editor for Flow Invocable Action with List Property

lightning-web-componentsvisual-workflow

I have an Apex Invocable action that takes a list of values in each request. Can I write an LWC Custom Property Editor to configure that list?

Here's what I've tried:

Apex Invocable Action (obviously, it doesn't nothing yet, I'm just scaffolding out the parameters right now):

@InvocableMethod(Label='Map a value' ConfigurationEditor='c-flow-map-editor')
public static List<String> get(List<Request> requests) {
    List<String> results = new List<String>();

    return  results;
}


public class Request {

    @InvocableVariable
    public String thisKey;

    @InvocableVariable
    public List<KeyValue> keyValuePairs;
}

public class KeyValue  {

    @InvocableVariable
    public String key;

    @InvocableVariable
    public String value;
}

Then, in the Javascript of the c-flow-map-editor, I have code based on the example from https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.use_flow_custom_property_editor_action_example :

handleThisKeyChange(event) {
    this.handleChange(event, 'thisKey', 'String');
}

handleKeyValuePairsChange(event) {
    this.handleChange(event, 'keyValuePairs', 'List');
}

handleChange(event, name, newValueDataType) {
    if (event && event.detail) {
        const newValue = event.detail.value;
        const valueChangedEvent = new CustomEvent(
            'configuration_editor_input_value_changed',
            {
                bubbles: true,
                cancelable: false,
                composed: true,
                detail: {
                    name,
                    newValue,
                    newValueDataType
                },
            }
        );
        this.dispatchEvent(valueChangedEvent);
    }
}

This works fine for the thisKey property – it's just a String. But, the keyValuePairs property causes an error at runtime when it's trying to figure out what to do with the type I passed in the configuration_editor_input_value_changed. By stopping it in the browser debugger, I could see the list of types that appear acceptable (as an aside, I couldn't find this list in the documentation):

  • Apex
  • Boolean
  • Date
  • DateTime
  • Number
  • SObject
  • String
  • reference

This makes it look like a list is unsupported unless it can be done via the Apex type somehow.

I could just stuff the list into a Sting, and deserialise it later in Apex. But that's ugly and I'd rather avoid it.

Best Answer

Well, here's the solution I ended up with:

I changed the list parameter into a String serialised into JSON. Then, I used the getter/setter pattern from the example code to hide that fact from the rest of the LWC, serialising and deserialising in those getters/setters.

From the user's perspective, they set the list of values via a datatable. And from most of the code's point-of-view, it looks the parameter is a list.

So the LWC controller is like this:

get keyValuePairs() {
    const param = this.inputVariables.find(({ name }) => name === 'keyValuePairsString');
    const result = param != null ? JSON.parse(param.value) : [];

    // Provide an id for the datatable
    result.forEach((thisKeyValuePair, index) => thisKeyValuePair.id = index.toString());
    return result;
}

handleKeyValuePairsChange(newKeyValuePairs) {
    this.handleChange({detail : { value: JSON.stringify(newKeyValuePairs)} }, 'keyValuePairsString');
}

Obviously, we need to deserialise in Apex like this:

    List<KeyValue> keyValues = (List<KeyValue>)JSON.deserialize(firstRequest.keyValuePairsString, List<KeyValue>.class);

And the types in Apex are like this:

public class Request {

    @InvocableVariable
    public String thisKey;

    @InvocableVariable
    public String keyValuePairsString; // Serialised List<KeyValue>

    @SuppressWarnings('PMD.EmptyStatementBlock') // Default constructor is required to be used in Flow
    public Request() {
    }

    public Request(String thisKey, String keyValuePairsString) {
        this.thisKey = thisKey;
        this.keyValuePairsString = keyValuePairsString;
    }
}

public class KeyValue {

    @InvocableVariable
    public String key;

    @InvocableVariable
    public String value;

    @SuppressWarnings('PMD.EmptyStatementBlock') // Default constructor is required to be used in Flow
    public KeyValue() {
    }

    public KeyValue(String key, String value) {
        this.key = key;
        this.value = value;
    }
}
Related Topic