SFDC Stop - Always the latest about Salesforce


Full Tutorial Series with videos, free apps, live sessions, salesforce consulting and much more.


Telegram logo   Join our Telegram Channel

Monday 15 January 2024

Embed screen flow in LWC component: Pass data to screen flow and Receive data from Screen Flow

Hello Trailblazers,


You might have come across the below blog posts published by me in the past:

  1. How to pass data from lwc to screen flow in salesforce?
  2. How to pass data from screen flow to lwc in salesforce?


You might be thinking, what the heck are we doing in this post then???


Give me a moment to clarify: In the above posts, we actually embedded a LWC component within a screen flow and passed data to it/received data from it. However, in today's post, we're going to do exactly the opposite. We're going to embed a screen flow within a LWC component and pass data to screen flow, receive data from screen flow. We're going to use lightning-flow lwc component provided by salesforce in this tutorial. So, without spending much time on discussion. Let's begin!


First of all we're going to create a very basic LWC component called flowContainer which will have our flow. We're going to embed this component on the homepage just like other demo components which we created. The content of .meta-xml file for the same is provided below:

flowContainer.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>59.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>Flow Container</masterLabel>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

Screen Flow - Duplicate Contacts

Before jumping on to more LWC code, let's create our screen flow first. This flow, named as Duplicate Contacts, is going to do the following:

  1. Get the list of contact ids from flowContainer LWC
  2. Create a new account record
  3. Query the existing contact records using their ids, create a copy of those, tag them to the new account record and insert them in salesforce
  4. Pass the new account record id to flowContainer LWC

Follow the below steps to create our screen flow:

1. Go to setup. Search for flow and click the New Flow button

2. In the new flow screen, choose Screen Flow option and click Create

3. In the Toolbox on the left hand side, click New Resource. The inputs are provided below:
      Resource Type: Variable
      API Name: ids
      Description: List of contact ids
      Data Type: Text
      Availability Outside the Flow: Available for input

We basically created a collection variable ids here, which will receive the list of contact ids from our flowContainer LWC component. We checked Available for input as we're going to receive it's value from outside the flow i.e. from our LWC component.

Note: No need to check these boxes otherwise. I've seen a lot of developers checking both Available for input and Available for output boxes without any reason. Please see if you really need an input in this variable from somewhere outside the flow and then only check this checkbox.

Before moving ahead, let's save the flow using the Save button on the top right. Click the Save button, fill in the details as shown below and click the save button present on the popup again to save the flow.
      Flow Label: Duplicate Contacts
      Flow API Name: DuplicateContacts
      Description: This flow will duplicate existing contact records based on ids and link them with a new account record

Inside this flow, we want to have a screen first which will create a new Account record. But before that, we need a resource of type Variable and object as Account. The details of the new resource is provided below:
      Resource Type: Variable
      API Name: NewAccount
      Description: This variable will store the new account record which is created
      Data Type: Record
      Object: Account

The screen to create a new account is provided below:

The header is: Enter Account Details
We added a single textbox in this screen which will store the Account Name as provided below:

Note that we switched to the Fields tab, populated the RecordVariable with our NewAccount variable that we created before and then we dragged + dropped the Account Name field to the screen. This will automatically bind the value entered by the user to the Name field of our NewAccount variable.

Now, we can add the Create Records element to our flow in order to insert this new account record. The details of Create Records element are provided below:
      Label: Create Account
      API Name: Create_Account
      Description: Insert the account record present in NewAccount variable in salesforce
      How Many Records to Create: One
      How to Set the Record Fields: Use all values from a record
      Record: NewAccount
Once our account record is created, we need to duplicate contact records and attach them to this new account record. In order to do it, we're going to use our Get Records element to query the contact records using ids. The details are provided below:
      Label: Query Contacts
      API Name: Query_Contacts
      Description: Query contact records based on record ids passed to the flow
      Object: Contact
      Filter: Id In {!ids}
      Sort Order: Not Sorted
      How Many Records to Store: All records
      How to Store Record Data: Automatically store all fields
If you notice above, we're using the {!ids} variable here which will have the ids of our existing contact records to query them. Now, we're going to remove the Id from these contact records to create new records, tag them to the newly created account and store them in a list.

In order to do that, we need a Loop element using which we'll loop all the queried contacts. The details of the same are provided below:
      Label: Iterate Contacts
      API Name: Iterate_Contacts
      Description: Iterate the queried contacts
      Collection Variable: {!Query_Contacts}
      Direction: First item to last item

Let's create a new list first to store our modified contact records which we're going to insert. The details are provided below:
      Resource Type: Variable
      API Name: contactsList
      Description: List of contact records
      Data Type: Record
      Object: Contact
      Allow multiple values (collection): True

Now, inside this loop, we'll set the Id and AccountId for every contact using an assignment element and add that contact record to a new list of contacts: contactsList which we created before.

The details for the same are as follows:
      Label: Set Id and AccountId
      API Name: Set_Id_and_AccountId
      Description: Set Id as empty and AccountId using the Id of newly created account for the current contact record
      Variable values:
      {!Iterate_Contacts.Id} <Equals> <Blank>
      {!Iterate_Contacts.AccountId} <Equals> {!NewAccount.Id}
      {!contactsList} <Add> {!Iterate_Contacts}

After this screen we'll use the Create Records element to insert contactsList in salesforce. The details for the same are provided below:
      Label: Create Contacts
      API Name: Create_Contacts
      Description: Insert the list of newly created contact records in salesforce
      How Many Records to Create: Multiple
      Record Collection: contactsList


One thing that we should update here is our NewAccount variable. We want to redirect the user to the newly created account record from our flowContainer LWC component. That means, we need to pass the new account from flow to LWC. Therefore, we can set Availability Outside the Flow as Available for output as shown below:

Now, our flow is complete. Make sure to Activate the flow. It's time to move on to the html code for our LWC component.

flowContainer.html

This component will basically show a button, which will launch our screen flow. Let's see the code:
<template>
    <template lwc:if={showFlow}>
        <lightning-flow
            flow-api-name="DuplicateContacts"
            flow-input-variables={inputVariables}
            onstatuschange={handleStatusChange}>
        </lightning-flow>
    </template>
    <template lwc:else>
        <lightning-button label="Duplicate Contacts" onclick={launchFlow}></lightning-button>
    </template>
</template>
As you can see above, we have two templates rendered on the basis of a boolean showFlow which is used in lwc:if attribute added in a template tag. If showFlow is true, we're displaying the DuplicateContacts screen flow in our lwc component using lightning-flow tag. If you notice inside lightning-flow tag, we've specified value for 3 attributes:

  1. flow-api-name: This should be the API name of the flow. For our flow, it's DuplicateContacts.
  2. flow-input-variables: This refers to the array of input variables i.e. the flow variables whose values we're going to pass from this LWC component.
  3. onstatuschange: We're capturing the statuschange event here and calling our handleStatusChange method. statuschange event is fired whenever the status of the flow is changed. For example: when the flow is started/paused/finished etc.

We're going to define showFlow, inputVariables - variables and handleStatusChange method in our js file. In the lwc:else section, we have a lightning-button whose label is Duplicate Contacts and on clicking of that button we're calling our launchFlow method which we're going to define in our js file which will launch our flow. So, let's move on to our js file to complete this component.

flowContainer.js

This is the most important part of the tutorial as this is where we're going to pass data from LWC to screen flow and we're going to receive data from screen flow in our LWC component. Let's take a look at the code below:
import { LightningElement } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';

export default class FlowContainer extends NavigationMixin(LightningElement) {

    // * Boolean to display/hide flow
    showFlow = false;

    // * Ids of contact records to be passed to flow
    contactIds = [
        '003H3000001l11BIAQ',
        '003H3000001l11AIAQ',
        '003H3000001l112IAA'
    ];

    // * Input variables to pass to flow from LWC
    inputVariables = [
        {
            name: 'ids',
            type: 'String',
            value: this.contactIds
        }
    ]

    /**
     * @description This method is used to launch the flow from lwc
     */
    launchFlow() {
        this.showFlow = true;
    }

    /**
     *
     * @param {object} event status change event - received when flow state is changed
     * @description This method will be called whenever the state of the flow is updated
     */
    handleStatusChange(event) {
        if(event.detail.status === 'FINISHED') {
            let accountVariable = event.detail.outputVariables?.find(
                outputVariable => outputVariable.name === 'NewAccount'
            );
            this.navigateToRecordPage(accountVariable.value.Id);
        }
    }

    /**
     *
     * @param {string} recordId Id of the record
     * @description This method is used to navigate the current user to the detail page of the record whose id is passed as parameter
     */
    navigateToRecordPage(recordId) {
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: recordId,
                actionName: 'view',
            },
        });
    }
}
Let's understand the above code line by line. First of all we imported NavigationMixin from lightning/navigation library. We're going to navigate to the record page of our newly created account record using this method. We also updated our FlowContainer class to extend NavigationMixin(LightningElement) for the same purpose.

We introduced three variables in our js file:

The first one is showFlow, which is a boolean variable and is false by default. This variable will be toggled to true when we want to display the flow in our LWC component. Remember the lwc:if condition in our HTML which is using this variable? If you check the HTML again you'll notice that by default our lightning-button will be visible through the lwc:else condition as showFlow is false.

The second one is contactIds, which is a string array that consist of the ids of contact records. We're going to pass this array to our flow ids variable.

The third one is inputVariables array, which is passed to our lightning-flow's flow-input-variables attribute. This is basically an array of objects, where each object is having a name, a type and a value. For each variable that we want to populate in our flow, through our LWC, we should have an entry for that in this array.

In each object inside our inputVariables array:
  • The name should be the name of the variable as defined in our flow. For our entry it's ids as we defined ids variable in the flow which will store the contact ids.
  • The type is the data type of the variable. In our case it's String (Text in flow)
  • The value should be the value of the variable defined in our flow. For our scenario, we want to pass the list of contact ids as value to our ids variable. Therefore, we've referred to our contactIds variable here which is defined above in the js and passed that as the value for our ids flow variable.

Note: I'm re-iterating the same thing so that you don't miss this. If you notice, this is the point where we've defined that: in the ids variable of our screen flow, we want to pass the array of contact ids we've hardcoded in our js. This value can come from different sources depending upon your use case. For example: You can have a lightning-datatable where you can select some records and as the records are selected, you can populate the contactIds array. This array will automatically be passed to the ids variable in the flow as the flow is launched. 

After that we've defined 3 methods which are as follows:

  1. launchFlow(): This method will be called when we click Duplicate Contacts button in our HTML. It'll set showFlow attribute to true which will automatically hide the button and will show the screen flow in our LWC. In a way we can say, this method is used to launch our screen flow.

  2. handleStatusChange(event): This method will be called whenever the flow status is updated. It's binded to statuschange event of our lightning-flow component. Inside this method, we need to check: If the flow is finished, we need to redirect the user to the detail page of newly created account record. We're receiving event inside this method as a parameter so, we're basically checking here if: event.detail.status === FINISHED i.e. if the flow is finished, we're referring to the outputVariables in our flow using event.detail.outputVariables to get the newly created account record.

    Remember that Available for output checkbox which we checked in our NewAccount variable inside the flow? That was marked so that it's value can be accessed outside the flow. Therefore, that variable will be received in the array of our ouputVariables accessed through event.detail.outputVariables.

    I'm sharing the NewAccount flow variable below again for your reference:
    As you can notice, we marked this as Available for output so that we can receive the value of this variable outside the flow i.e. in our case - inside our flowContainer lwc component. If you log event.detail.outputVariables, you'll get an array as shown below:
    As you can see above, there is only a single entry in this array and that is for our NewAccount variable. It's name property is having a value as NewAccount, it's objectType is Account. This variable is not a collection so isCollection is false. It's coming from flow DuplicateContacts so the flow name is the same and it's dataType is SOBJECT as it stores the value of an sObject record. Moving onto the value property, as we only populated the name of the account while creating the record from flow, it's value is an object having only two properties: Id and Name.

    Moving back to our code, we are using find() method to find the outputVariable from our outputVariables array where name = NewAccount. This will return us the first entry of our array. We're storing this in a js variable named accountVariable. Finally, we're accessing this account record's id using accountVariable.value.Id and passing it to our navigateToRecordPage() method which will navigate the current user to the new account's record page.

    Note: This is the point where we're receiving data from flow in our LWC component. The variables present in our flow which are marked as available for output, will be received in our LWC component inside outputVariables array under our event.

  3. navigateToRecordPage(recordId): This method is used to navigate the current user to the detail page of the record whose record id is passed as a parameter. This method is called from handleStatusChange() method. We're using NavigationMixin.Navigate to navigate to the standard record page and we're passing recordId as the value to our recordId attribute.

That's all for our js part as well! Let's embed our component inside the homepage and see how it works. Take a look at the demo below:
As you can see above, as we clicked on Duplicate Contacts button in our LWC, the screen flow launched. We entered the account name in the screen flow which created a new account named My Account and all the 3 contacts (whose ids we hardcoded in our js) are duplicated and attached to this new account record. We finally received this new account record in our js as the flow finished and navigated to the account detail page using our LWC.

If you see below, we have all the 3 newly created contacts linked to the same My Account record, however the old contacts are present as is and linked to their own account records.

That's all for this tutorial, I hope you liked it. Let me know your feedback in the comments down below.

Happy Trailblazing!!

No comments:

Post a Comment