6

I've build a navigation LWC with a Custom Property Editor to be used in a Flow Screen.

The Flow has a Screen with a checkbox 'cancelCheckbox'. When the agent ticks that checkbox, the red button 'Cancel' should appear. When the checkbox is not checked, the red Cancel button should disappear.

enter image description here

I did not find a way to bind Flow Variables to my Custom Property Editor. I can add Numbers, Toggles, all beautiful, but how do I bind a Flow variable to my LWC input?

enter image description here

Would I not use a Custom Property Editor, I could have used the default input fields, like picture below. Is such input field available for Custom Property Editors? Am I missing this information in the documentation? I have read a lot of documentation, but nothing seems to help here. enter image description here

So the question is: How do I bind a Flow Screen variable to a LWC Custom Property Editor input? Thanks in advance!

1 Answer 1

1

Binding flow variables to your CPE is possible for flow variables, based on simple atomic types (Strings, Dates and Integers etc), as well as for record variables, Apex-defined types and arrays of all these, but not for certain special-purpose Flow variable types such as FlowDynamicChoiceSets. Salesforce themselves are clear that there are limits in this area.

In the simplest case of a Text flow variable:

  1. Add a target config string property corresponding to the text flow variable in your CPE's js-meta.xml:

        <property name="test" label="Test" type="String"/>
    
  2. Add a getter for variables from the builderContext in your CPE's js file:

get variableOptions() {
    const variables = this.builderContext.variables;
    return variables.map(({ name }) => ({
        label: name,
        value: name,
    }));
}
  1. Add a combobox to your CPE's html:
<lightning-combobox
    label="Variable Resource"
    value={variable}
    placeholder="Select choice set resource..."
    options={variableOptions}
    onchange={handleChangeVariable}>
</lightning-combobox>
  1. Add the handler to your js:
handleChangeVariable(event) {
    if (event && event.detail) {
        const newValue = '{!'+event.detail.value+'}';
        this.dispatchInputChanged('test', newValue, 'reference');
    }
} 

dispatchInputChanged(name, newValue, dataType){
    this.dispatchEvent(
        new CustomEvent(
            'configuration_editor_input_value_changed',
            {
                bubbles: true,
                cancelable: false,
                composed: true,
                detail: {
                    name: name,
                    newValue: newValue,
                    newValueDataType: dataType,
                }
            }
        )
    );
}

The only nifty bit is enclosing the variable name in {!...} and using the dataType reference when raising the configuration_editor_input_value_changed event to notify the Flow engine of the selected text variable. (See unofficialSF deck on CPEs.) Thereafter, in the main LWC Flow component the property will be set to whatever value is in the variable at the time of invocation.

@api test;

Other supported options:

  1. Simple flow variables of other basic types such as Integer, Date, DateTime and Boolean (see Supported Types in Data flow). This option covers the OP's question - yes, it's possible!.
  2. Record variables of fixed sObject type. Set the property type to '@Salesforce/Schema/Account' or equivalent for your SObject. (see Alex Edelstein's helpful article)
  3. Record variables of generic sObject type. This is covered here.
  4. Apex-defined types where they correspond to some the 'Apex defined' type flow variable.
   <property name="questions" label="Questions" type="apex://cbpApiNameLabel[]"/>
public with sharing class cbpApiNameLabel {
    @AuraEnabled public String apiName;
    @AuraEnabled public String label;
    public cbpApiNameLabel(String apiName, String label) {
        this.apiName = apiName;
        this.label = label;
    }
    public cbpApiNameLabel(){
    }
}
 @api get questions(){
    const questions =  this.inputVariables.find(({name}) => name === 'questions');
    return questions? questions.value: [{apiName:'', label:'', key:'0', keyt:'0t'}];
 }

Check out this great article for more detail.

  1. Collections of all the above types, by adding '[]' to the end of the data type and passing in an array to the associated CustomEvent's Detail.newValue property.

What confused me initially, was understanding whether I always had to have an existing Flow variable underlying each CPE inputVariable, or whether the CPE admin can define inputVariables directly. The documentation suggests that you can either set values via a reference to some flow variable "{!myVar}", or directly with literal strings or arrays of things assigned to the '... value changed...' event's detail.newValue field. In reality, I found that while simple atomic types work fine without an underlying Flow variable, composite types (SObject records, Apex-defined types and all arrays) only work in conjunction with a reference to an existing flow variable of that exact type. If like me, you were hoping to use these composite types to pass back configuration values from the CPE to its parent Flow Screen Component, I fear it's maybe not possible currently. I'd typically get this error on closing the CPE:

This page has an error. You might just need to refresh it. [Cannot read properties of undefined (reading '1')] Failing descriptor: {markup://builder_platform_interaction:elementFactory}

But you can serialise these composite types into simple Strings, for which, no underlying Flow variable is required - see for example, here.

Also unsupported seems to be access to special-purpose flow variable types such as Choices and DynamicChoiceSets, where they are not persisted as sObjects and the corresponding Apex class is not published by Salesforce. Salesforce themselves are clear that there are limits (again see Supported Types in Data flow). But if you want your CPE to help with building picklists, you can always access existing picklist values directly using the Lightning Data Service and @wire and then pass these back to the screen component using an Apex-defined JSON bean.

Hope this helps a bit, for those that follow!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .