Configuration Component

If you have a more complex configuration for your extension, we’ve got you covered. You can write a custom Lightning component and the Valence UI with instantiate it, pass configuration data back and forth with it, and save that configuration data back to the server for you. Using a Lightning component is mutually exclusive with using a configuration structure.

Each Valence interface relating to configuration has a method that asks for your “configuration Lightning component”. You return null if you’re not using a custom component, or the fully-qualified name of your component if you are.

Both Aura and Lightning Web Components are supported (but do yourself a favor and go with LWC). In either case, you always need to return the name in the Aura-style naming convention.

Valid Names

c:MyAuraComponentConfigurator c:myLightningWebComponentConfigurator mynamespace:myLightningWebComponent

Invalid Names

c-my-lightning-web-component-configurator c:my-lightning-web-component-configurator

Note

Aura components tend to start with an uppercase letter; LWCs always start with a lowercase letter.

Tip

If you are getting a red error message about component creation in the UI when you are expecting to see your configuration component, you probably got the name wrong in your return string!

Interacting With Your Valence Container

Your component is instantiated inside of a smart container that will provide you with some useful context information, manage your configuration state (is dirty / discard changes), and allow users to persist your configuration data back to the server (save changes).

Context

Much like your Apex class receives a LinkContext, your component will receive information about what is going on around it. Define properties with these names and they will be set by the container.

Configuration

This is your configuration that will be stored in the database and given to your extension during Link runtime. Valence serializes this object as a JSON string and that string is what you are given in the setConfiguration() Apex method during Link execution.

For the purposes of your custom UI, you do not have to worry about getting an existing configuration out of the database, or persisting a new or updated one back to the database. This is all handled by Valence. If an existing configuration exists, it will be passed to your component at instantiation inside this attribute, otherwise you’ll be given an empty object. Modify this object to your heart’s content, and when the user eventually clicks the Save button your configuration will be serialized and stored.

Schema

Schema information about this Link (full list of possible source fields, full list of possible target fields). Because fetching schema can be slow, schema is set asynchronously. It will be set with a blank value when your component is constructed, and then updated several seconds later with actual schema data. Be sure to check for that blank value and don’t do anything with it until real data is populated.

Mapping

If this is an Filter extension that implements ConfigurablePerMappingFilter, this property will also be set with information about the specific mapping your configuration will be attaching to.

Events

There is one event the container listens for from your component.

updateconfig

Fire this event whenever your configuration is modified, even if it’s still a work in progress. Use isValid to share your opinion about whether the configuration as it stands is acceptable.

Event name: updateconfig Param: newValue - a javascript object that is the entire configuration Param: isValid (optional) - true/false for whether this configuration should be allowed to be saved to the server (enables/disables the Save Changes button)

Subclassing the Valence Configurator Component

We hate boilerplate code if you haven’t noticed. Even though interacting with your Valence container is straightforward, we maintain a Lightning Web Component service component that you can extend to make it even easier. Unfortunately Salesforce does not currently allow you to extend a Lightning Web Component from a namespace other than c and lightning, so rather than include it in the package we have it on GitHub and you’ll need to pull it down and put it into your org.

import ValenceUIConfigurator from 'c/valenceUIConfigurator';

export default class MyAwesomeConfigurator extends ValenceUIConfigurator {

If you extend our component, it will handle working with the context properties, expose some lifecycle functions for you to take advantage of, and generally make you go “ahhh, yes”.

Abstract Methods

There are two methods you must implement in your subclass.

getDefaultShape()

Return a starter object that has some reasonable defaults for your configuration.

getDefaultShape() {
        return {'eggPreference' : null, 'baconPreference' : false};
}

computeValid()

Calculate if the current configuration values look good to you and should be allowed to be saved to the server.

computeValid() {
        return !!this.configuration.eggPreference; // check if eggPreference is a truthy value and return a boolean true/false
}

Lifecycle Methods

There are a number of methods you can add to your subclass to be notified when each of the context properties are set. This is especially useful for schema, since it is loaded asynchronously and set more than once.

They have no parameters, simply check the property itself to use the new value.

onSetLink()
onSetSchema()
onSetMapping()
onSetConfiguration()
tweakConfiguration() - special lifecycle method allowing you to make changes to the configuration right before it is kicked up to the container

Example Usage of onSetSchema()

fieldChoices = []; // options for the lightning-combobox where the user picks the field they want to use

/**
 * Set up our fieldChoices whenever we are given schema
 */
onSetSchema() {

        if(!this.schema) {
                return;
        }

        // set up selection options for the field
        this.fieldChoices = [];
        Object.values(this.schema.Source.children).forEach((node) => {
                this.fieldChoices.push({'value' : node.field.fieldName, 'label' : node.field.fieldLabel});
                // note: we deliberately ignored any nested schema fields as they are unlikely to usable for what we're doing here
        });
        this.fieldChoices.sort((a, b) => a.value.localeCompare(b.value));
}

Example Usage of tweakConfiguration()

It’s not unusual for the format of the configuration that works for the Apex class to not work that well in the user interface when working with Lightning components. One way to handle this is to transform the configuration property to suit your needs in the interface. This hook lets you transform it back so you don’t persist a format or extra keys you didn’t want to. This example comes from our open-source Object Builder Filter.

/**
 * Because combobox has to work with a string value and sourcePaths are arrays, we enrich each configuration record with a flattened path
 */
onSetConfiguration() {
        this.configuration.fields = this.configuration.fields.map(field => Object.assign({'flattened' : field.sourcePath.join('::')}, field));
}

/**
 * This is called just before sending the configuration up the chain. We strip out the extra key we added to each `fields` entry.
 */
tweakConfiguration() {
        return {
                'resultName' : this.configuration.resultName,
                'fields' : this.configuration.fields.map(field => {
                        return {'fieldName' : field.fieldName, 'sourcePath' : field.sourcePath};
                })
        };
}

Utility Methods

Here are the utility methods that exist in the superclass you can invoke to help out.

configUpdated()

Call this method whenever you have made changes to the configuration property. It lets the container know and also invokes the computeValid() method.

trackChange()

You bind this directly to the change event on your form components so that you don’t even need to do anything with them in your controller, but their value will still be set in the configuration.

Be sure to set the name attribute on the form component to the exact configuration property you want it to write to.

<lightning-input type="checkbox"
                                 checked={configuration.baconPreference}
                                 name="baconPreference"
                                 label="Do you want bacon on the side?"
                                 onchange={trackChange}></lightning-input>

debounceChange()

Same as trackChange(), but it debounces the input first to smooth it out. Preferred for fields where the user is typing the input.

You bind this directly to the change event on your form components so that you don’t even need to do anything with them in your controller, but their value will still be set in the configuration.

Be sure to set the name attribute on the form component to the exact configuration property you want it to write to.

<lightning-input value={configuration.eggPreference}
                                 name="eggPreference"
                                 label="How do you like your eggs?"
                                 onchange={debounceChange}></lightning-input>