/lwc-utils

Reusable LWCs to 10x your solution building speed. Design interactive, data-dense UIs with LWC + Screen Flows.

Primary LanguageJavaScriptBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

LWC Utils

Reusable LWCs to 10x your solution building speed.

  • messageService: Lightning Message Service (LMS) simplified component messaging.
  • SOQL Datatable: Leverage SOQL to power your list views, related lists, and even Screen Flows.
  • Collection Datatable: Manage Record Collections variables in Screen Flows.
  • Design patterns leveraging both Aura and LWC to dynamically create dialogs (modals) for better UX.
  • Launch Screen Flows dynamically inside a dialog (modal) from anywhere.

In this README:

Introduction

This repo showcases the best defaults for creating rich, interactive, data-dense UIs using the following centerpieces:

  • lightning-datatable from LWC.
  • lightning:overlayLibrary from Aura.
  • lightning:flow from Aura.
  • Lightning Message Service to stitch it all-together.

Salesforce has invested heavily into LWC, Flow and Screen Flow and has given Architect Guidance around how to build scalable and flexible solutions now and into the future.

This repo builds on that guidance and pushes data-dense UI design to the next level with highly reusable, highly configurable components. These components have saved me thousands of developer hours and allowed me to pivot on a dime to meet the changing speed of business.

I hope they will help you do the same.

Component Library Overview

Component Name Description Component Type
messageService

Example
Code
Use one API to communicate within or across both Aura and LWC technologies.

Use this component instead of manually publishing / subscribing to Lightning Message Service (LMS).

Provides a psuedo-namespacing property called boundary which can separate subscribers by string, recordId etc.
LWC:
- Service
DialogService

Example
Code
Provide LWCs access to lightning:overlayLibrary to create dialogs (modals) via LMS.

Both Aura and LWCs can be created dynamically and injected as the dialog body.

Both Aura's public attributes and LWC's @api properties can be passed in.
Aura:
- Service
MessageServiceHandler

Example
Code
Provides access to DialogService by handling the opendialog LMS event.

This is a hidden component you need to place on the flexipage or utility bar (hidden, empty label).
Aura:
- Service
- Utility Bar
- Record Flexipage
EventFooter

Code
Dynamic footer for lwc dialogs. Meant to be used by DialogService.

Contains an instance of messageService listening for the closedialog LMS Event.

Unfortunately, component.getReference() does not work on LWCs. Write your own action button in the dialog body.
Aura:
- Service
ModalFooter

Code
Dynamic footer for aura dialogs. Meant to be used by DialogService.

Connects a primary action on the target dialog body to the footer's main action via component.getReference()

Enables writing functions directly on the dialog body and DialogService.modal() will connect it to a primary action.
Aura:
- Service
FlowWrapper

Example
Code
Helps with dynamic flow creation, for example, inside a dialog body created from DialogService.

Can be used with dialogAutoCloser on the final screen to automatically close a Flow.

See flowWizardLauncherExample
Aura:
- Service
dialogAutoCloser

Example
Code
Contains a progress bar and timer message (optional).

Automatically publishes a closedialog LMS event and bubbles the same closedialog Custom Event when timer hits 0.

Use uniqueBoundary to target a specific dialog to close if Tab-Focused Dialogs is Enabled
LWC:
- Service
- Flow Screen
soqlDatatable

Example
Code
A SOQL powered list view.

Meant to replace any related list / list view.

Supports record context, in-line editing, configurable table/row actions, output of selected rows to Flow (or other LWCs) and more.

See example for full features.
LWC:
- Service
- App Flexipage
- Record Flexipage
- Flow Screen
collectionDatatable

Example
Code
Display Record Collections inside Flow Screens.

Meant to mimic a related list / list view.

Can be populated from a Flow's Get Records or soqlDatatable.selectedRows output.
LWC:
- Flow Screen

messageService

Designed to ease the friction of inter-component (and technology) communication. This component is both the publisher and the subscriber to reduce implementation friction.

With that design, it's important to leverage the boundary property to properly scope your event publisher/listeners.

Some components in this library, like soqlDatatable, will generate a UUID to help scope payloads to its own child components (custom data type cells, dialogs etc).

This component uses Lightning Message Service on OpenChannel__c to message payloads in a key / value format as defined in OpenChannel__c like this:

const payload = { 
    key: 'coolevent',
    value: {
        hello: 'world',
        foo: 'bar'
    }
}
this._messageService.publish(payload);

// or, my preferred method, this way

const payload = {
    accountId: '12345'
}
this._messageService.publish({key: 'supercoolevent', value: payload});

And handled like this, composed on the template:

<c-message-service
    boundary="sample_app_lwc"
    oncoolevent={handleCoolEvent}
    onsupercoolevent={handleSuperCoolEvent}
></c-message-service>
handleCoolEvent(event) {
    console.log(event.detail.value.hello) // world
    console.log(event.detail.value.foo) // bar
}

handleSuperCoolEvent(event) {
    const payload = event.detail.value
    console.log(payload.accountId) // 12345
}

This component doesn't need to subscribe to an event, it can be used for publish only:

<!-- No listeners, but has a boundary set for any publish() calls -->
<c-message-service boundary={recordId}></c-message-service>

... or

<!-- No listeners, no boundary set for any publish() calls -->
<c-message-service></c-message-service>

This component also provides public methods to Aura only APIs like overlayLibrary.

For example, using .dialogService() ultimately routes to DialogService.cmp:

const dialogServicePayload = {
    method: 'bodyModalLarge',
    config: {
        auraId: 'soql-datatable-example',
        headerLabel: 'Dynamically Created SOQL Datatable',
        component: 'c:soqlDatatable',
        componentParams: {
            isRecordBind: false,
            recordId: this.recordId,
            queryString: query
        }
    }
};
this._messageService.dialogService(dialogServicePayload);
messageService Specification

Attributes

name type access required default description
boundary string public no Filter subscription messages like a namespace.

e.g. recordId if you only want same components on same record flexipage to handle the publish.

e.g. sample_app_lwc as reference among various components that share the same functionality.

Enablement of APPLICATION_SCOPE like in this diagram is not currently enabled.

Public Methods

name arguments description
dialogService (payload) payload is in the shape required by MessageServiceHandler. Examples:
flowWizardLauncherExample
lwcContactDatatable
soqlDatatableLauncherExample
notifyClose Uses publishOpen to fire a closedialog LMS Event which will close any dialog opened by DialogService
publish (payload) Leverages LMS's publish functionality.
Defaults to no boundary.
If boundary is set, all subscribers will require the same boundary.
publishOpen (payload) Leverage LMS's publish functionality without boundary. Any subscriber can react to this event.
// TODO Useful for closedialog unless this critical update is enabled.
// TODO When a user can simultaneously open multiple dialogs in service console, it's better to set a boundary.
forceRefreshView Uses eval("$A.get('e.force:refreshView').fire();"); directly.
notifySuccess (title, message = null) Convenience function for ShowToastEvent
notifyInfo (title, message = null) Convenience function for ShowToastEvent
notifySingleError (title, error = '') Convenience function for ShowToastEvent.
error object can be passed directly in, it will be reduced/parsed by c-utils.reduceError.

DialogService

This component is composed inside MessageServiceHandler and provides it with the public methods for creating modals via Aura's overlayLibrary.

Primarily used by messageService for message publishing, MessageServiceHandler receives the subscription and delegates to this component.

It is not recommended to use this component directly.

DialogService Specification

Attributes

name type access required default description
overlayPromise Object public no Stores the returned overlay promise from overlayLibrary.

If a callback is specified by the caller, this is returned.

Public Methods

Arguments for this component are not in JS Object {} notation so that they can be explicitly listed out in the component itself.

For that reason, it is recommended to use messageService / MessageServiceHandler to call these functions.

name arguments description
showPopover (
body,
bodyParams,
referenceSelector,
cssClass,
callback
)
No examples for this one yet.
modal (
auraId,
headerLabel,
body,
bodyParams,
mainActionReference,
mainActionLabel,
callback,
)
Compatible with Aura dialog bodies.

body is the component name (Aura notation) to be created in a dialog.

bodyParams are public attributes to be passed from the caller to the body.

mainActionReference uses component.getReference to connect the primary action in ModalFooter to a function on the body to be created.
This allows you to avoid writing a button specifically at the bottom of the body to be created.

mainActionLabel changes the label of the primary action on ModalFooter.

callback is optionally specified to return the overlayPromise if needed. Alternatively, listen for the dialogready LMS Event.
modalLarge (
auraId,
headerLabel,
body,
bodyParams,
mainActionReference,
mainActionLabel,
callback,
isLargeModal = true
)
Compatible with Aura dialog bodies.

Same as modal, with wider dialog box using slds-modal_large
bodyModal (
auraId,
headerLabel,
body,
bodyParams,
callback
)
Compatible with LWC dialog bodies.

Same as modal except without connectivity to a mainAction via component.getReference which doesn't work on LWCs, even with @api functions.

Instead, a slim footer called EventFooter is created which is subscribing to the dialogclose event for closing the dialog.

Write your own Cancel and Primary Action button on the dialog body that is dynamically being created.
bodyModalLarge (
auraId,
headerLabel,
body,
bodyParams,
callback,
isLargeModal = true
)
Compatible with LWC dialog bodies.

Same as bodyModal, with wider dialog box using slds-modal_large

MessageServiceHandler

As of early Summer 20, Lightning Message Service requires rendering on the DOM to be connected.

Because of this limitation, this component is designed to be placed once on the utility bar (rendered, but hidden label) OR per flexipage.

The primary use case for this component is to parse the messageService.dialogService() payload. It expects two properties:

const flowOrDialogServicePayload = {
    method: 'bodyModal', // or bodyModalLarge, flowModal, flowModalLarge
    config: {
        <see flowWizardLauncherExample>
        <or soqlDatatableLauncherExample>
    }
}

This component is very simple which just listens and delegates to DialogService.

It can easily be extended to include other Aura only APIs, such as lightning:workspaceAPI.

<aura:component implements="lightning:utilityItem">
    <c:DialogService aura:id="dialogService" />
    <c:messageService aura:id="messageService" onopendialog="{! c.handleDialogService }" />
    <c:singleton aura:id="singleton" />
</aura:component>
MessageServiceHandler Specification

Attributes

None

Public Methods

None

FlowWrapper

This component is designed to help launch flows dynamically, from any LWC click event.

This powers configurable flow actions (table and row) on soqlDatatable by being dynamically created inside a dialog.

The component itself is very simple, as it's meant to be called via DialogService which creates an instance of it:

// DialogService.executeDialogService()
...

    if (payload.method.startsWith('flow')) {
        flowModalConfig = {
            auraId: 'flow-wizard-container',
            headerLabel: payload.config.flowHeaderLabel,
            component: 'c:FlowWrapper',
            componentParams: {
                flowApiName: payload.config.componentParams.flowApiName,
                inputVariables: payload.config.componentParams.inputVariables
            }
        };
    }

...
<aura:component>
    <c:messageService aura:id="messageService" />
    <aura:attribute name="flowApiName" type="String" access="PUBLIC" />
    <aura:attribute name="inputVariables" type="Object[]" access="PUBLIC" />
    <aura:handler name="init" value="{! this }" action="{! c.doInit }" />
    <div class="slds-is-relative">
        <lightning:flow aura:id="flow" onstatuschange="{! c.handleStatusChange }" />
    </div>
</aura:component>
FlowWrapper Specification

Attributes

name type access required default description
flowApiName String public yes Developer Name of the flow to be dynamically created by lightning:flow
inputVariables Object[] public yes Array of inputs in flow's [{ name: 'flowVarName', type: 'String', value: 'my cool string value!' }]

Public Methods

None

dialogAutoCloser

A simple component that counts down and auto closes a DialogService opened dialog by sending a messageService connected closedialog event.

This is meant to be used with DialogService when launching a Screen Flow as the final step.

However, there are a couple more ways to use it:

  • As a visual countdown progress bar, handling the bubbled closedialog Custom Event by yourself.
  • Refreshing an instance of soqlDatatable by using the uniqueBoundary and isRefreshTable properties.
    • This sends a boundary scoped: refreshsoqldatatable LMS event.

NOTE: It is recommended you provide this component a uniqueBoundary scoped to its caller, otherwise it may close more dialogs than intended if Tab-Focused Dialogs is enabled.

<template>
    <c-message-service></c-message-service>
    <lightning-layout horizontal-align="center" multiple-rows>
        <lightning-layout-item flexibility="shrink">
            {messageTemplate}
        </lightning-layout-item>
        <lightning-layout-item size="12">
            <lightning-progress-bar value={progress}></lightning-progress-bar>
        </lightning-layout-item>
    </lightning-layout>
</template>
    @api messageTemplate = 'Auto closing in {timer} seconds';
    @api timer = 5;
    
    ...

    renderedCallback() {
        if (this._isRendered) {
            return;
        }
        this._isRendered = true;
        this._startProgressInterval();
        this._startTimerInterval();
    }
dialogAutoCloser Specification

Attributes

name type access required default description
messageTemplate String public no Auto closing in {timer} seconds Message to display to user while countdown is running
timer Number public no 5 Seconds until the component launches the closedialog LMS event

Public Methods

None

soqlDatatable

Create a fully featured lightning-datatable with just a SOQL String.

This component can be used on a Flexipage as a list view or a related list. This can even be used inside Screen Flows.

Since this is built on top of the lightning-datatable base component, all the bells and whistles can be inherited.

The below example showcases how easy it is to create a soqlDatatable right in the Lightning App Builder with the following query string:

SELECT Name, Email, Phone, LeadSource, Level__c, AccountId, Account.Type FROM Contact LIMIT 50

soql-datatable-app-builder

soqlDatatable - Features and Examples

Using Record Context with $CurrentRecord in the SOQL

$CurrentRecord and $recordId are special syntax that allows for merge-fields of current record data into the SOQL string. By using them, you can merge current record context as values in the WHERE clause as follows:

// Find other Accounts similar to this Account's Industry
SELECT Name, Type, Website, Industry
FROM Account
WHERE Industry = $CurrentRecord.Industry
AND Id != $recordId

// Find related contacts with same MailingState as this Account's BillingState
SELECT Name, Email, MailingState, Account.BillingState
FROM Contact
WHERE AccountId = $recordId
AND MailingState = $CurrentRecord.BillingState

This uses Lightning Data Service (getRecord) to retrieve and resolve the record values, so make sure your user(s) have FLS enabled for any fields you plan on using the $CurrentRecord feature with.

All data types that can be SOQL-ed are supported for $CurrentRecord.

Please submit issues to this repo if you find one that cannot be merged correctly.

Row Selection Events and Flow outputs

When this component's checkboxType is configured to Multi or Single, the base datatable emits a rowselection event which can be handled by any parent LWC:

// datatable.js
case 'rowselection': {
    this.dispatchEvent(
        new CustomEvent('rowselection', {
            detail: { selectedRows: this.selectedRows },
            bubbles: true,
            composed: true
        })
    );
    break;
}
<c-soql-datatable
    ...
    onrowselection={handleRowSelection}
    ...
></c-soql-datatable>
handleRowSelection(event) {
    console.log(event.detail.selectedRows); // this.selectedRows from base datatable.js
}

This component also outputs selectedRows and firstSelectedRow to Flow screens as output variables. See the specification section for details.

Inline / Mass Inline Editing

Define which fields can be editable in a comma separated list in the Editable Fields design attribute. For data types that are supported in the vanilla lightning-datatable, such as date, text, number, those are relied on as heavily as possible.

Note: All edits on save will be saved to database using Lightning Data Service updateRecords. Errors will be handled using lightning-datatable formatted error handling.

For data types such as picklist and lookup which are yet to be supported, this component provides custom data types as follows.

Picklist Custom Data Type

This custom data type is surfaced as customPicklist. It always places a --None-- value, regardless of if your picklist is configured to always require a value. The save will fail and user will need to correct it to move on.

RecordType restricted picklist values are supported with a limitation:

When using mass edit on a Picklist field for a Standard Object enabled with Record Types, it's possible to mass apply a value which does not belong on that table. This seems to be because Standard Object picklist fields do not have the Restrict picklist to the values defined in the value set option.

The actual picklist edit cell is a fork of the one authored by jlyon87 as found here

Lookup Custom Data Type

The custom LWC data type is surfaced as customLookup.

Each soqlDatatable can be have one defined Lookup Configuration (Datatable_Config__mdt) to define lookup search behavior.

Because of a limitation with cmdt, the Type__c on the parent Datatable_Config__mdt must be Lookups.

When using inline edit and lookup, there are two properties that are set as global defaults on Datatable_Lookup_Config__mdt that help with the search results:

  • Title: Name of the Record
  • Subtitle: null

However, in this sample repo, they are overridden by the following settings:

soql-datatable-lookup-defaults.png

Which produces this kind of search result:

The actual lookup edit cell is a fork of the one authored by jlyon87 as found here

Supported Features for all Custom Data Types

  • Multi-line inline edit (aka mass-edit).

  • Partial save across rows is supported.
    • Error display user experience is aligned to native list views.
    • If one row errors, all fields/columns for that row fail as well until all errors are resolved.

Unsupported / Roadmap Features

  • Keyboard navigation.
    • Pending lwc / aura issue investigation here.
  • Geolocation fields must be queried with the __Longitude__s and __Latitude__s (capital L).
  • Time data type is not yet supported for view or edit.
Column Sorting

Add a list of Field API names to the sortableFields property to enable this feature. Parent notation (one level up) is supported.

Optionally, set default Sort Field and Sort Direction to have the asc/desc indicator automatically show when the table is initialized.

Multi-sort and filtering will not be supported.

Global search is on the roadmap (like regular list views)

Configurable Flow and LWC actions

Each soqlDatatable can be have one defined Action Configuration (Datatable_Config__mdt) to define both Table level (supporting multi / single select) and Row Level actions. This can be the same Datatable_Config__mdt as used in the Lookup Configuration section.

Because of a limitation with cmdt, the Type__c on the parent Datatable_Config__mdt must be text of Actions. For combined configs, use Actions; Lookups.

Both LWCs (inside a dialog) and Screen Flows can be launched from either action type. The configuration is easier to explain in picture format:

soql-datatable-config-mdt

Assign New Account - Flow Table Action

The button is configured to the SOQL_Datatable_Flow_Action_Update_Contacts_with_New_Account Screen Flow.

soqlDatatable sends the following inputVariables to Flows.

All of the following must be implemented as variables if the Screen Flow backs an action, otherwise you will get an error.

Name Type Value
SelectedRows SObject[] Choose the correct Object type in a Record Collection.
FirstSelectedRow SObject First Selected Row, choose the correct Object in a Record variable.
UniqueBoundary String For dialogAutoCloser to refresh the table that opened the Screen Flow.
SourceRecordId String The recordId of the page that the soqlDatatable is placed on.

When the flow is done, it auto-closes using dialogAutoCloser.

soql-datatable-new-account-flow

Note: Due to how data is constructed in soqlDatatable, you cannot use the SelectedRows directly in a Update Records. Always assign values you specifically want to update to a new Record Variable that is not an output of soqlDatatable, which in this example is ContactShell/ContactToUpdate.

Check Opportunities - LWC Table Action

This button configured to open the checkOpportunitiesExample LWC.

Notice the public attributes, these are always supplied by soqlDatatable when invoking an LWC.

<template>
    <c-message-service boundary={uniqueBoundary}></c-message-service>
    <template if:true={queryString}>
        <c-soql-datatable query-string={queryString}></c-soql-datatable>
    </template>
    <template if:false={queryString}>
        <div class="slds-align_absolute-center">
            No Contacts Selected. Please choose contacts to view opportunities for.
        </div>
    </template>
</template>
...

@api uniqueBoundary;
@api selectedRows;
@api sourceRecordId;

queryString;

// private
_isRendered;
_messageService;
_accountIdSet = new Set();

connectedCallback() {
    if (this.selectedRows && this.selectedRows.length) {
        this.selectedRows.forEach(row => {
            this._accountIdSet.add(`'${row.AccountId}'`);
        });
    }
    if (this._accountIdSet.size > 0) {
        let accountIds = Array.from(this._accountIdSet.keys());
        this.queryString = convertToSingleLineString`
            SELECT Account.Name, Name, Amount, CloseDate, StageName
            FROM Opportunity
            WHERE AccountId IN (${accountIds.join(',')})
            ORDER BY Account.Name ASC
        `;
    }
}

...

Remove Phone - Flow Row Action

The button is configured to the SOQL_Datatable_Flow_Row_Action_Remove_Contact_Phone Screen Flow.

This Screen Flow also auto-closes with dialogAutoCloser.

soql-datatable-remove-contact-phone-flow

Note: Due to how data is constructed in soqlDatatable, you cannot use the FirstSelectedRecord directly in an Update Records. Always assign values you specifically want to update to a new Record Variable that is not an output of soqlDatatable, which in this example is ContactToUpdate.

Dynamic Creation via MessageService & DialogService

Dynamically create a soqlDatatable when clicking the Launch a SOQL Datatable in a Dialog button.

This is the psuedo-code of what happens:

button.js calls messageService.dialogService(payload)
    => button.js composed instance of messageService uses LMS to...
        => Another composed instance of messageService in MessageServiceHandler.cmp (label-less in utility bar)
            =>  CustomEvent opendialog is bubbled and handled in...
                => MessageServiceHandler.cmp component.finds()...
                    => DialogService.cmp
                        => DialogServiceController.js
                            => $A.createComponent('c:soqlDatatable')
                                => lightning:overlayLibrary

Here's the actual payload used in the above code flow:

handleOpenDialog() {
    const query = convertToSingleLineString`
        SELECT Title, Name, Email, Account.Name, Account.Type
        FROM Contact
        LIMIT 5
    `;
    const dialogServicePayload = {
        method: 'bodyModalLarge',
        config: {
            auraId: 'soql-datatable-example',
            headerLabel: 'Dynamically Created SOQL Datatable',
            component: 'c:soqlDatatable',
            componentParams: {
                isRecordBind: false,
                recordId: this.recordId,
                queryString: query
            }
        }
    };
    this._messageService.dialogService(dialogServicePayload);
}

As you can see, it's possible to parameterize a payload back to Aura's $A.createComponent API to instantiate a public properties against an LWC.

soqlDatatable Specification

Attributes

name type access required default description
isRecordBind Boolean public true Only on Record Page. Use $CurrentRecord or $recordId in your SOQL query to use record context. User must have FLS access.
title String public no
showRecordCount Boolean public false
showRefreshButton Boolean public false
queryString String public yes Order of fields in the SOQL string determine order of columns. Parent (one level) relationships supported (e.g. Account.Type)
checkboxType String public no None None, Multi, or Single (outputs radios). This allows the component to emit the rowselection event.

For Screen Flows this populates the selectedRows and firstSelectedRow output variables.
editableFields String[] public no Comma separated list of Field API names for inline editing. Does not support parent relationship (Account.Type). Saving writes to server.
sortableFields String[] public no Comma separated list of Field API names. Parent relationship is supported (e.g. Account.Type).
sortedBy String public no Single Field API Name. Parent relationship is supported (e.g. Account.Type).
sortedDirection String public no asc
actionConfigDevName String public no Not available on Flow Screen. Configure table and row actions with a record in Datatable_Config__mdt.
lookupConfigDevName String public no Not available on Flow Screen. Configure inline edit lookup search behavior with a record in Datatable_Config__mdt.
useRelativeMaxHeight Boolean public false Force table height to 60% of the vertical screen space.
selectedRows SObject[] public Uses FlowAttributeChangeEvent to notify changes to Flow Screens.
firstSelectedRow SObject public Uses FlowAttributeChangeEvent to notify changes to Flow Screens.

Public Methods

name arguments description
refreshTable Refreshes the table (imperatively).

collectionDatatable

This component is designed for use with Screen Flows to display tables of data from a Record Collection.

You can use Get Records elements or selectedRows from SOQL Datatable.

This was designed to provide data dense feedback to the user on what they're working on in a Screen Flow.

collection-datatable-tab.png

collectionDatatable - Features and Examples

Manipulate a Record Collection

This example shows inline editing (single and mass) as well as how to handle saving edited records afterwards.

collection-datatable-manipulate.png

Show Selection in Collection Datatable

This Screen Flow uses the ability for soqlDatatable to output a directly to collectionDatatable.

Note: You can also assign soqlDatatable's selectedRows output to a Record Collection variable as well.

With Flow Inputs and Collection Datatable

Details incoming...

Inline / Mass Inline Editing

Define which fields can be editable in a comma separated list in the Editable Fields design attribute. See soqlDatatable - Features and Examples for full details.

Note: All edits on save will not be saved to database. All error handling on edited rows must be handled by your flow manually.

Column Sorting

Same as soqlDatatable. See soqlDatatable - Features and Examples for full details.

collectionDatatable Specification

Attributes

All of the following are available as Flow output variables.

name type access required default description
selectedRows SObject[] public When checkboxType is set to Multi or Single, this has selected rows.
firstSelectedRow SObject public First selected row.
editedRows SObject[] public When editableFields is used AND the datatable is Saved, this outputs only edited rows.
allRows SObject[] public When editableFields is used AND the datatable is Saved, this outputs all rows.

Deploy (Unlocked Package)

LWC Utils

This unlocked package contains only the lib, no examples (recipes) that showcase their implementations. If you're working with this library for the first time, I recommend you install the "LWC Utils Recipes" in a sandbox after you install this.

Sandbox: https://test.salesforce.com/packaging/installPackage.apexp?p0=04t1Q000001QhOyQAK

PROD: https://login.salesforce.com/packaging/installPackage.apexp?p0=04t1Q000001QhOyQAK

LWC Utils Recipes

This unlocked package must be installed after the above. This cannot be installed in PROD.

Sandbox: https://test.salesforce.com/packaging/installPackage.apexp?p0=04t1Q000001QhP3QAK

Configuration and Getting Started

With the "LWC Utils Recipes", two sample apps (LWC Utils and LWC Utils Console) have been included to showcase various ways to implement the library.

There are also many example Flows that have been set up as well.

After installation, please review the following:

  • Datatable_Config__mdt
  • Datatable_Lookup_Config__mdt
  • Datatable_Action_Config__mdt

For soqlDatatable to successfully launch any configured Table / Row action (Flow and LWC) you must:

  1. Map a Datatable_Config__mdt that has a Type__c field that contains the text Actions.
  2. Place MessageServiceHandler somewhere on the App / Record Flexipage or the Utility bar. This component launches dialogs/modals.

For soqlDatatable inline editing of any Lookup data types, you must:

  1. Map a Datatable_Config__mdt that has a Type__c field that contains the text Lookups. Actions; Lookups is a valid configuration.
  2. Review the Datatable_Lookup_Config.Default_Lookup_Config and any necessary Object specific overrides.