Adding Lightning Web Components to Flow Screens

Note! This is a preview of Winter ’20 Functionality

For the last two years, Flow creators have been able to add lightning component to Flow Screens. This has powerfully extended the capability of screens. We’ve had a great time creating reusable components as a community, and many of those components are available for use to all parties.

The underlying web technology enabling these components, known as Aura, has served Salesforce well, but it’s more than 5 years old, and that’s a long time when it comes to changes in web technology. Salesforce recently released a major upgrade to its web technology called Lightning Web Components, and the Flow team has been working on making it possible to embed this new generation of components into Flow screens. With the Winter ’20 release, that will be now be possible, so let’s take a look at how it’s done.

In this demonstration, we create an LWC that allows the user to manually add and manage sharing settings on a record. This allows a Sharing button to be placed on Lightning record pages. The guts of this component consist of code written by resident Salesforce evangelist Shane McLaughlin.

To get an LWC to appear in Flow’s Screen Builder, you add a ‘lightning_FlowScreen’ target to the component’s meta file:

To expose attributes from the LWC, you first use @api in the LWC’s javascript, as is standard for any property you want to make accessible outside of the component:

Then you additionally specify which of these public properties should be additionally made visible in Flow by adding a targetConfig section:

The type field supports the same types that Flow supports with aura components. That includes specific Sobjects like “Contact” and specific SObject collections like “Account[]”.

Note the following syntax for specifying SObjects and Apex Classes:

  • @salesforce/schema/<name of sObject>
  • apex://<name of Apex class>
  • add array notation if it is a collection []

with a namespaced org you have to include the namespace in the type string using the namespace prefix. So, for SObjects it would look like type=”@salesforce/schema/myNs__CoolCustomObject__c” and similarly for apex type=”apex://myNs__MyApexClass”

The ‘role’ parameter can be added to property elements inside of targetConfigs. It has been created specifically to provide support for Flow’s ability to limit access to inputOnly or outputOnly. If no role is specified, the property is available in both directions.

Considerations When Working With Targets

Be Careful about Mixing Your Targets

The support mentioned above for SObjects and Apex Classes works only for Flow and not for other targets like lightning__RecordPage. So something like this will fail:

This can be hard to debug because the each target has its own validation, but the errors reported back don’t specify which target is having a problem. So we’ve seen cases where people think that Flow is complaining when it’s App Builder that’s complaining.

Each property has to meet the requirements of each Target that mentions it.

Example: App Builder (and thus lightning__RecordPage, lightning__AppPage, lightning__HomePage) requires that if you add a ‘required’ attribute you also have to add a ‘default’ attribute. Flow does not have this requirement.

I’m finding the safe thing to do is to separate the App Builder targets from the Flow target, like this:

This doesn’t eliminate all problems. In the example above, Flow is forced to add a default attribute to editTabName because editTabName is also used in the AppBuilder targets, where that required/default issue is enforced. But it makes it easier to debug because you can comment out one set and see which validation is causing problems.

Events and Notification

Unlike Aura, the parent component doesn’t automatically learn when something changes in the child component.

To notify the runtime of changes in the value of an attribute, the component must fire the FlowAttributeChangeEvent event. For example, if you’ve exposed an attribute in your component and want the value of that component to be available downstream in the flow, you need to fire this event whenever the value changes so that the Flow runtime component will have the latest value when the user clicks Next (For architectural reasons, the Flow runtime doesn’t have the ability to read the values of the attributes of its child components).

In the following example, a ToDo LWC dispatches a FlowAttributeChangeEvent when a new item is added to the list of To Do’s:

import { LightningElement, api, track } from 'lwc';
import { FlowAttributeChangeEvent, FlowNavigationNextEvent } from 'lightning/flowSupport';
export default class Todos extends LightningElement {
    @api
    availableActions = [];
    @api
    get todos() {
        return this._todos;
    }
    set todos(todos = []) {
        this._todos = todos;
    }
    @track _todos = [];
    get hasTodos() {
        return this._todos && this._todos.length > 0;
    }
    handleUpdatedText(event) {
        this._text = event.detail.value;
    }
    handleAddTodo() {
        this._todos.push(this._text);
        // notify the flow of the new todo list
        const attributeChangeEvent = new FlowAttributeChangeEvent('todos', this._todos);
        this.dispatchEvent(attributeChangeEvent);
    }
    handleGoNext() {
        // check if NEXT is allowed on this screen
        if (this.availableActions.find(action => action === 'NEXT')) {
            // navigate to the next screen
            const navigateNextEvent = new FlowNavigationNextEvent();
            this.dispatchEvent(navigateNextEvent);
        }
    }
}

See additional pieces of the To Do example

Validation

To link an LWC into Flow’s validation framework, create a function called “validate” in your js file:

@api
validate() {
    if(/* true conditions */) { 
         return { isValid: true }; 
        } 
    else { 
    //If the component is invalid, return the isValid parameter as false and return an error message. 
         return { 
               isValid: false, 
               errorMessage: '/*A message that helps your user enter a valid value or explains what went wrong.*/' 
                }; 
     }}) 
}

Navigation

To programmatically transition a Flow with an LWC component, you dispatch an event using this syntax:

import { LightningElement, api } from 'lwc';
import { FlowNavigationNextEvent } from 'lightning/flowSupport';

export default class NameOfYourComponent extends LightningElement {

   @api
   handleGoNext() {
       const nextNavigationEvent = new FlowNavigationNextEvent();
       this.dispatchEvent(nextNavigationEvent);
   }
}

The supported events are:

  • FlowNavigationNextEvent
  • FlowNavigationBackEvent
  • FlowNavigationFinishEvent
  • FlowNavigationPauseEvent

Sample Gists

https://gist.github.com/alexed1/e3e580103375120ca2dc1374bb4f73ff

Flow Actions for Strings: URL Encoding and Number Formatting

Arnab Bose contacted me this morning and wanted a couple of Flow Actions for transforming strings. He’s building some cool Flow and Quip integrations and needed a way to easily take a string with spaces and URL Encode it so he could put it in a URL (for example: ‘my cat’ becomes ‘my+cat’). He also had some numbers in string form that he wanted to add commas to (i.e convert 2348934 to 2,348,934).

In Apex, these are super simple because of the large library of available functions. To URL encode a string, you just write:

String encoded = EncodingUtil.urlEncode(myString, 'UTF-8');

and to format a string, you can just write:

response.outputStr = Integer.valueOf(inputStr).format()

But the fun part of Flow is not having to write code. So I created a couple of Apex Actions that carry these out:

You can install these from here.

The source code is available here and is a great template to convert other Apex string functions.

Easy “IN” Filters in Flow with the FilterCollection Flow Action

Intro Video

SOQL provides a useful IN operator that filters the query on a specific set of values:

credit: https://www.salesforcetutorial.com/soql-in-operator/

You currently can’t do this directly in the Flow Builder Get Records element, but you can install this FilterCollection Flow Action to provide the capability.

Out of the box, this action is set up to support standard objects: Contact, Account, Opportunity, Lead, Product, Case. You can easily modify it in Apex to support additional objects of your choice (see customization, below).

Installation

Instructions

For our example, we want to query for all accounts that have an Industry that’s IN Banking or Chemicals. We expect to get back three of these four accounts:

Configure this Action by passing three pieces of information:

  1. A collection of SObjects. You can pick from the supported list. At this moment, 5 standard objects are supported. You can only pass in a single collection of SObjects. Leave the other inputs blank.
  2. ‘filterField’: The name of the field on your SObject that you want to filter on. In our example we’ll set this to Industry.
  3. The target values. These are equivalent to ‘Rose’ and ‘Sean’ in the above example image. In our example, we’ll pass in Banking and Chemicals. You can pass the values in either as a single comma-separated list in the targetValuesCSVString input, or as a collection of strings in the targetValuesStringCollection (don’t use both at the same time).

Here’s an example of a properly configured set of inputs:

This action will return a corresponding collection of filtered objects. Make sure you create a collection variable of the appropriate Record type and map it in the Store Output Values tab.

Optional: Customization

The following information is for advanced Flow users and discusses how this action can be modified to support additional types of objects. A current limitation in Flow makes it so that Apex Actions have to add specific code for each specific sObject they want to support (it’s on the roadmap to eliminate this limitation). So the bad news is that only 5 common standard objects are currently supported in FilterCollection.

The good news, though, is that it’s easy to add support for additional standard objects and custom objects.

To add support for an additional object, you have to add code in four places. First, add an input variable to the Requests inner class and an output variable to the Results inner class:

To process the input collection, add a code block based on the five lines immediately below. This has the effect of casting (transforming) your specific SObject collection to a general SObject collection. Then at the end, add a when clause to the switch statement to cast the general filtered-down collection back to the specific SObject type that Flow needs:


If you do add more standard objects, please consider making a pull request to the source code so everyone can benefit from your work!

Source Code

TDX Session Video:Building Advanced Flows with Choices, Loops, and New Apex-defined Types

Here’s a broadcast of one of the two Advanced Flow sessions from TDX.

Flow Action: Get Picklist Values

In my spare time I’m experimentally rebuilding Approval Processes on top of Flow and I recently had a need for a way in Flow to retrieve a set of picklist values that I could then work with. So I built a simple Flow Action to enable all flow designers to do this without code.

It’s a little like the Picklist Choice Set resource in that you hand it the name of an Object and a Field, but it returns a collection of strings that you can then work with directly.

You can iterate through the values but one of the most useful things to do with this is to pass them into the new multiselect dual listbox screen component to let the user pick from among them.

Documentation

Provide this action with the api names of your target Object and Field. Field must be a picklist.

Install (Unmanaged Package)

Source Code

Scaling to Thousands of Screens with Lightning Flow

In the common diagnostic use case, you have a tree structure of information and you work your way through the tree, gathering information and using it to determine the next diagnostic question. This is useful for important and distinctive use cases like troubleshooting and coming up with a good offer. Here’s an example:

Now, you can see four screens in this flow, and creating four screens isn’t too hard, especially with Flow Builder’s Duplicate tool. However, what if you have 500 of these screens? And what if this content is constantly changing and you want to make it possible for non-Admins to maintain it?

There’s a great way to address this use case, and I call it the Troubleshooter pattern. In this pattern, you don’t insert the content into screen elements. Instead you insert it into records of a custom object. Then you use a single Screen to load the appropriate custom object’s content for display. Part of the content includes a set of choices that the user can use to signal where they want to go next. Each choice points to a target set of content.

Here’s the entire flow used to show the above content:

Two custom objects have been created here:

DiagnosticNode represent a screenful of information. It includes a rich text content field to display to the agent or user or technician. It also contains a radio button group that gets loaded with all of the node’s child DiagnosticOutcomes.

DiagnosticOutcome represents a single choice/answer that might come out of a particular DiagnosticNode. It will render as a radio button choice and has two important properties: the Label and a lookup to a different “Target” DiagnosticNode.

The beautiful thing about this approach is that the creation, editing, reporting, analytics of the content nodes themselves is all done with regular Salesforce records. For example, if I want to build out my tree of decisions, I first create a new target DiagnosticNode:

And then add as many different destination outcomes as I want:

Sources of Content

The flow can display content either from the rich text “Node Content” field on the DiagnosticNode custom object or from a Knowledge article. To use Knowledge, check the box on a DiagnosticNode and select the desired article.

Editing Content

A button at the bottom of the page provides easy access to the record containing the content being looked at. This makes use of a custom Flow Screen Component called Navigation Button.

git source for the full project (including Knowledge support)

Install the Sample Flow Shown Above. (NOTE: The sample does not have the Knowledge support because of a packaging problem, but it’s easy to add).

  1. To install, you may need to:Create Custom Tabs for Diagnostic Node and Diagnostic Outcome in Setup –> Tabs
  2. Turn on visibility for each of the fields in Diagnostic Node and Diagnostic Outcome (to do this, use Object Manager, select each field, and then click on Set Field-Level Security
  3. Manually create at least one Diagnostic Node to serve as your initial node. The sample flow currently asks for the ID of that initial node. Get it from the URL.

Hosting Components on UnofficialSF

When we learn about a good component, we seek to:

  1. create a page for it on unofficialsf. This can either be a Post or a Page.
  2. make sure the install instructions on that page provide links to unmanaged and managed packages.

Managed packages can be important if there are collisions between support files. For example, many components use Andy Fawcett’s metadata service. You can install a new component that has this apex class via an unmanaged package if you already have that class on your org. The Managed Package process puts each component into its own namespace.

Each dev edition org can only host a single managed package. Fortunately they’re free. If you’re trying to create a managed package for your component, do the following:

  1. Create a new free Developer Edition at https://developer.salesforce.com/signup
  2. Deploy your component to this edition and create an Unmanaged Package in the Package Manager
  3. Create a Managed Package of that component. For namespace, use usf_mycomponent, where mycomponent is similar to the name of your component. So if you’re publishing a Lookup component you might pick usf_lookup as your namespace. Use “Release” and not “Beta” in your settings
  4. Test that your packages work and then publish the links

Minimize the Window When a Utility Bar Flow is Finished – Evan Ponter

By Evan Ponter

Flows are a great way to collect information from your users in a guided fashion. They can be added to the utility bar of an app for easy access no matter where the user navigates. But the normal behavior for flows in utility bars is an endless loop – when the flow ends, the first screen is shown again. This doesn’t always make sense for each flow you are distributing. Wouldn’t it be nice if you could have the flow window minimized when the flow ends?

Introducing the Minimize Utility Item component. With the addition of this action element to the end of your flow logic, you can tell the flow to minimize its window. There are no inputs or outputs specified for this element – just connect it within your flow canvas and the flow’s window will be minimized at that point in the flow interview execution. As an added bonus, components on the current page will be refreshed with any info that was manipulated in your flow.

If you distribute your flow in multiple locations, only the flow in the utility bar will see the effect of this element. A flow that is launched from a record action will behave as-if this Minimize Utility Item element were not in the flow at all.

Getting Your Users Attention with Custom Notifications

Andy Fawcett explains how to use Notification Builder to add custom notifications with Process Builder and flows. He includes an ingenious method to use custom metadata types to get the notification ID for a subflow.

Getting Your Users Attention with Custom Notifications