Pages

Showing posts with label Lightning Web Components. Show all posts
Showing posts with label Lightning Web Components. Show all posts

Friday, July 31, 2026

How to Use DML When Using Lightning Web Component for Quick Action

How to Use DML When Using Lightning Web Component for Quick Action

Lightning Web Components (LWC) aren't just for record pages and app screens — they can also power Quick Actions, giving users a fast, focused way to create or update records without leaving the page they're on. But since LWC itself can't talk to the database directly, any DML (Data Manipulation Language) operation — insert, update, delete, or upsert — has to go through Apex.

This post walks through exactly how that wiring works: building an LWC-based Quick Action, calling an Apex method to perform DML, and handling the response so the action closes cleanly and refreshes the page.

Why Use LWC for a Quick Action?

Salesforce Quick Actions can be built a few different ways — standard record-creation actions, Flow-based actions, or a custom Lightning Web Component quick action. The LWC route is worth reaching for when you need:

  • Custom validation logic before saving
  • A tailored layout that doesn't match the standard object layout
  • Multiple related records created or updated in a single click
  • Conditional UI (showing/hiding fields based on other values) that a standard action can't easily do

Step 1: Build the LWC Component

Any LWC used as a Quick Action needs to implement lightning__RecordAction in its target configuration, and its JavaScript class needs access to the current record's ID (passed in automatically as recordId).

HTML Template

<template>
    <lightning-card title="Log a Follow-Up Task">
        <div class="slds-p-around_medium">
            <lightning-input
                label="Subject"
                value={subject}
                onchange={handleSubjectChange}>
            </lightning-input>

            <lightning-input
                type="date"
                label="Due Date"
                value={dueDate}
                onchange={handleDueDateChange}>
            </lightning-input>

            <lightning-button
                variant="brand"
                label="Save"
                onclick={handleSave}
                class="slds-m-top_medium">
            </lightning-button>
        </div>
    </lightning-card>
</template>

JavaScript Controller

import { LightningElement, api } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { CloseActionScreenEvent } from 'lightning/actions';
import { updateRecord } from 'lightning/uiRecordApi';
import createFollowUpTask from '@salesforce/apex/QuickActionController.createFollowUpTask';

export default class LogFollowUpTask extends LightningElement {
    @api recordId; // Automatically populated with the current record's Id

    subject = '';
    dueDate = '';

    handleSubjectChange(event) {
        this.subject = event.target.value;
    }

    handleDueDateChange(event) {
        this.dueDate = event.target.value;
    }

    handleSave() {
        createFollowUpTask({
            whatId: this.recordId,
            subject: this.subject,
            dueDate: this.dueDate
        })
        .then(() => {
            this.showToast('Success', 'Follow-up task created.', 'success');
            this.dispatchEvent(new CloseActionScreenEvent());
        })
        .catch((error) => {
            this.showToast('Error creating task', error.body.message, 'error');
        });
    }

    showToast(title, message, variant) {
        this.dispatchEvent(new ShowToastEvent({ title, message, variant }));
    }
}

A few details worth calling out:

  • @api recordId is what makes this component aware of which record launched the action — Salesforce populates it automatically when the component is used as a Quick Action.
  • CloseActionScreenEvent is what closes the Quick Action panel after a successful save. Without dispatching it, the modal stays open even after the DML succeeds.
  • ShowToastEvent gives the user immediate feedback, whether the save succeeded or failed.

Step 2: Write the Apex Controller That Performs the DML

The actual insert/update logic lives in Apex, exposed to the LWC through an @AuraEnabled method:

public with sharing class QuickActionController {

    @AuraEnabled
    public static void createFollowUpTask(Id whatId, String subject, Date dueDate) {
        try {
            Task t = new Task();
            t.WhatId = whatId;
            t.Subject = subject;
            t.ActivityDate = dueDate;
            t.Status = 'Not Started';

            insert t;

        } catch (DmlException e) {
            throw new AuraHandledException('Unable to save task: ' + e.getMessage());
        }
    }
}

A few best practices baked into this pattern:

  • with sharing ensures the DML respects the running user's record-level access, rather than silently bypassing it.
  • Wrapping the DML in a try/catch and re-throwing as AuraHandledException is essential — a plain DmlException won't surface a readable message to the LWC's .catch() block. AuraHandledException is specifically designed to safely pass error details back to client-side JavaScript.
  • Keep the method focused on a single responsibility. If you need to create multiple related records, build the full list of sObjects in Apex and perform one bulk DML call rather than several separate inserts.

Step 3: Handling Bulk or Related DML Safely

If your Quick Action needs to create or update more than one record — say, a Task and a related Note — always batch the DML into a single call per object type rather than looping inserts one at a time:

@AuraEnabled
public static void createTaskWithNote(Id whatId, String subject, Date dueDate, String noteBody) {
    try {
        Task t = new Task(
            WhatId = whatId,
            Subject = subject,
            ActivityDate = dueDate,
            Status = 'Not Started'
        );
        insert t;

        ContentNote note = new ContentNote();
        note.Title = subject + ' - Notes';
        note.Content = Blob.valueOf(noteBody);
        insert note;

        ContentDocumentLink link = new ContentDocumentLink();
        link.ContentDocumentId = [SELECT ContentDocumentId FROM ContentVersion WHERE Id = :note.Id].ContentDocumentId;
        link.LinkedEntityId = t.Id;
        link.ShareType = 'V';
        insert link;

    } catch (Exception e) {
        throw new AuraHandledException('Unable to save task and note: ' + e.getMessage());
    }
}

This keeps all the DML server-side in one transaction, so either everything saves together or nothing does — avoiding a half-completed state if one insert fails partway through.

Step 4: Refreshing the UI After a Quick Action

Because the DML happens in Apex and not through Lightning Data Service, the record page won't automatically reflect the change once the action closes. Two common approaches:

Option A: Refresh the view using RefreshEvent

import { RefreshEvent } from 'lightning/refresh';
// ...
this.dispatchEvent(new RefreshEvent());

Option B: Use getRecordNotifyChange from Lightning Data Service

import { getRecordNotifyChange } from 'lightning/uiRecordApi';
// ...
getRecordNotifyChange([{ recordId: this.recordId }]);

Either approach tells the platform's caching layer that the underlying record has changed, so any related lists, related record fields, or other components on the page pick up the fresh data without a full page reload.

Step 5: Configuring the Quick Action in Setup

Once the component is deployed, expose it as a Quick Action from Setup:

  1. Go to Object Manager → select your object → Buttons, Links, and Actions.
  2. Click New Action.
  3. Set Action Type to Lightning Web Component.
  4. Choose your LWC from the Lightning Web Component picklist (only components with lightning__RecordAction in their js-meta.xml will appear here).
  5. Give the action a Label and Name, then save.
  6. Add the new Quick Action to the object's page layout so it appears as a button.

Here's the required js-meta.xml configuration for the component to be selectable as a Quick Action:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>60.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>Log Follow-Up Task</masterLabel>
    <targets>
        <target>lightning__RecordAction</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordAction">
            <actionType>ScreenAction</actionType>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

Common Pitfalls to Avoid

  • Forgetting CloseActionScreenEvent. Without it, users are left staring at a modal that appears to do nothing after clicking Save, even though the record saved successfully.
  • Not wrapping DML in a try/catch. Uncaught Apex exceptions return a generic, unhelpful error to the LWC — always catch and re-throw as AuraHandledException with a clear message.
  • Looping DML statements inside Apex. Even in a Quick Action context, build lists and insert/update them once outside of loops to respect governor limits and avoid hitting DML row limits on records with many related children.
  • Skipping the refresh step. Users expect the page to reflect their change immediately — dispatching RefreshEvent or calling getRecordNotifyChange closes that gap.
  • Missing with sharing. Leaving the controller class as without sharing (the Apex default) means the DML runs with elevated access regardless of the user's actual permissions — a subtle but serious security gap.

Key Takeaways

  • LWC Quick Actions can't perform DML directly — all inserts, updates, or deletes must go through an @AuraEnabled Apex method.
  • Use with sharing on your Apex controller and wrap DML in try/catch, re-throwing as AuraHandledException so errors surface cleanly in the LWC.
  • Dispatch CloseActionScreenEvent after a successful save so the action panel closes automatically.
  • Use RefreshEvent or getRecordNotifyChange to make sure the record page reflects the change immediately.
  • For multi-object DML, batch everything into one Apex transaction rather than multiple round trips, so the whole operation succeeds or fails together.

With this pattern, you get the flexibility of a fully custom UI for your Quick Action, backed by clean, governor-limit-friendly Apex DML — giving users a fast, reliable way to create or update records without ever leaving the record page.

Thursday, January 20, 2022

Share JavaScript Code Between Lightning Web Components

Hello Friends, as you know that writing the reusable code good into Development /implementation .

Create Shared Code

To share code between components, create an ES6 module and use the standard export statement to export the functionality that your module exposes. Your module can use the standard import statement to use other shared modules

utils LWC Component 

  export default shpwToast (variant='info', mode='dismissable', title, message) {
const event = new ShowToastEvent({ title: title, message: message, mode : mode, variant : variant }); return event; }
Note :- with in this component no html will be there.

Use Shared Code

To use the shared code in a JavaScript file, use the standard import statement. For example:

import {
    shpwToast 
} from 'c/utils';

This line imports the utils module in the c namespace.