Launch a Reusable lightning-modal LWC containing a dynamically determined Flow…from an Aura Component
Related References:
- lightning-modal guide
- lightning-flow guide
- Source – DemoLightningModal
- Other Helpful Posts Related to Topic:
- Greytrix – How to invoke an LWC Component function from Aura Component
- Techdicer – Call LWC from Aura Component
- SalesforceCodes – How to use a lightning web components(LWC) inside an aura component
Background
Legacy orgs will have a number of Aura Components that have yet to be transitioned to Lightning Web Components. LWCs have added a number of standard components that make working with them far easier and more performant. What if you have an existing Aura Component that cannot be easily migrated (or at least not yet), but you’d still like to launch or interact with an LWC such as lightning-modal in the meantime? No problem – we can add reference to an LWC in an Aura Component, and call methods against that LWC.
In this example, we’ll look at an Aura Component that includes a button to launch an LWC utilizing lightning-modal and lightning-flow within that modal. This approach can be used in a variety of other ways, but this should give a good idea of how it works. Prior to the release of Dynamic Actions, a ‘banner component’ was a common approach to the conditional rendering of actions, so if you’ve employed such a component, this may be of special help to you.
Create a Generic Modal Component
First we’ll create a generic LWC Modal component that accepts reference to a particular Flow along with associated attributes. This will allow us to launch a Flow within a modal from an Aura Component, while dynamically passing in the Flow name, attributes and/or behaviors for the modal. See lightning-modal and lightning-flow documentation for additional details here.
<template>
<template lwc:if={showHeader}>
<lightning-modal-header label={header}></lightning-modal-header>
</template>
<lightning-modal-body>
<template lwc:if={flowModal}>
<div class="slds-is-relative">
<lightning-flow
onstatuschange={handleStatusChange}
flow-api-name={flowName}
flow-input-variables={inputVariables}
flow-finish-behavior={flowFinish}
>
</lightning-flow>
</div>
</template>
</lightning-modal-body>
<template lwc:if={showFooter}>
<lightning-modal-footer>
<lightning-button label="Close" onclick={handleClose}></lightning-button>
</lightning-modal-footer>
</template>
</template>
import { api } from 'lwc';
import LightningModal from 'lightning/modal';
export default class TestModal extends LightningModal {
/* FLOW PROPERTIES */
@api header;
@api flowName;
@api inputVariables;
@api flowModal = false;
@api showFooter = false;
@api showHeader = false;
@api flowFinish = 'NONE';
handleStatusChange(event) {
if(event.detail.status === 'FINISHED'){
this.close('flow finished: '+this.flowName);
}
}
handleClose(){
this.close('modal is closed');
}
}
Create an LWC Launcher that Calls the Modal Component
Now we’ll create an LWC that will be embedded within the Aura component, and which imports the TestModal LWC created previously. Any functions that should be visible to the Aura component will be decorated with @api, which will allow targeting of the component from Aura, and thus invoking that method on the LWC. In this Launcher component, we’ll call the TestModal, and pass in the values for Flow (flowName here is the api name of the Flow we want to run inside the modal), display controls, and behaviors. Note that the template is empty (not included here even) as there is no display required here – write your Javascript file to suit your needs of course.
import { LightningElement, api } from 'lwc';
import testModal from 'c/testModal';
export default class TestLauncher extends LightningElement {
/* STANDARD ATTRIBUTES */
@api recordId;
/* FLOW ATTRIBUTES */
flowName;
inputVariables;
flowFinish = 'NONE';
size = 'large';
flowLabel = '';
showFooter = false;
showHeader = false;
flowDescription;
disableClose = false;
autoRefresh = false;
/* FLOW TYPES & ATTRIBUTES */
//Test Flow Launch
@api testFlow(){
this.size = 'full';
this.flowName = 'TestFlow';
this.flowLabel = 'Test Flow';
this.showHeader = false;
this.showFooter = false;
this.flowDescription = 'Test Flow';
this.inputVariables = [{
name: 'recordId',
type: 'String',
value: this.recordId
}];
this.flowFinish = 'STOP';
this.handleFlowModal();
}
/* FLOW MODAL OPENING */
async handleFlowModal() {
this.result = await testModal.open({
size: this.size,
flowName: this.flowName,
header: this.flowLabel,
flowModal: true,
showHeader: this.showHeader,
showFooter: this.showFooter,
inputVariables: this.inputVariables,
flowFinish: this.flowFinish,
desription: this.flowDescription,
disableClose: this.disableClose
});
}
}
Create or Update the Aura Component
Finally we add reference to the TestLauncher component in an existing or new Aura Component. The important part here is that when the associated button is clicked, we target the LWC and call the function associated with the button – here called ‘testFlow()’.
<aura:component implements="flexipage:availableForAllPageTypes,force:hasRecordId,force:appHostable">
<aura:attribute name="recordId" type="Id"/>
<c:testLauncher recordId ="{!v.recordId}" aura:id="testModal"></c:testLauncher>
<lightning:card title="Demo Aura Component">
<lightning:button
variant="brand"
label="Test Modal"
onclick="{!c.openTestModal}"
class="slds-m-around_x-small">
</lightning:button>
</lightning:card>
</aura:component>
({
openTestModal : function(component, event, helper) {
let testModal = component.find('testModal');
testModal.testFlow();
}
})
Test it Out
We have everything together now, and can launch the lightning-modal with embedded lightning-flow from the Aura component just created. The example Flow created here just allows a couple of fields on the Work Order object to be updated.
Wrapping Up
Thanks for reading, and hopefully you can put this approach to good use until all your Aura components are migrated to LWC.