Grid - Bulk Action

When it comes to updating the data from a grid, we might hit the limits like a CPU time, memory, DML.... To bypass those limitations, the updates should be executed in asynchronous mode using queueables or batches jobs.

To support this type of transactions, we provide GM - Bulk Action. With Bulk Action you get a framework to track the running tasks from a developer perspective. We also provide a monitor to visualise background tasks and let the users see the outcomes including the occurred errors.

Bulk Action Monitor Setup

To track the running bulk actions, the GM - Bulk Action Monitor should be configured on the Lightning App. Each app requiring this type of tracking should have this utility bar configured.

When the utility item is added, it should be configured as below. The width and the height should adjusted based on the label of actions, screen resolution...

Start automatically should be always checked for the monitor. If not we may loose initiated jobs before opening the monitor at the first time.

The cleanup delay defines the number of second before removing a successfully completed job. If you want your users to get a chance, put a long delay.

When a job is completed, the user get success toast message if the job is completed without any error. Otherwise he will get an error notification.

Bulk Action Implementation

Aura Action Component

Our monitor is configured, let's go ahead and start our first bulk action. Let's say that we want to move to close date by one day for the whole scope defined by the user.

This action will be triggered from an Opportunity grid. Let's create an Aura component TestBulkActionActionComponent. The component has all the required properties including:

  • Grid Name : Grid name coming from the configuration,

  • Grid Label : Grid label coming from the configuration,

  • Action Name : Action name coming from the configuration,

  • Action Label : Action label coming from the configuration,

  • Query : The SOQL query defining the scope

The component should also fire onsucess or oncancel based on the user flow. Finally we will use bulkActionPublisherLWC utility component to publish the job to the monitor. It's a useful component to streamline the implementation process.

<aura:component implements="force:hasRecordId" controller="TestBulkActionController" access="global">
    <!-- Action properties coming from GridMate-->
    <aura:attribute name="relatedObjectName" type="String" access="global" />    
    <aura:attribute name="gridLabel" type="String" access="global" />
    <aura:attribute name="gridName" type="String" access="global" />
    <aura:attribute name="gridCode" type="String" access="global" />
    <aura:attribute name="actionName" type="String" access="global" />
    <aura:attribute name="actionLabel" type="String" access="global" />

    <!-- Soql Query coming from GridMate-->
    <aura:attribute name="query" type="String" access="global" />

    <!-- Internal flag to control the spinner-->
    <aura:attribute name="isWorking" type="Boolean" access="global" />

    <aura:registerEvent name="onsuccess" type="gmpkg:DataGridActionEvent" />
    <aura:registerEvent name="oncancel" type="gmpkg:DataGridActionEvent" />

    <!-- overlayLib API -->
    <lightning:overlayLibrary aura:id="overlayLib" />
        
    <!-- Bulk Action Publisher -->
    <gmpkg:bulkActionPublisherLWC aura:id="bulkActionPublisher" />
    
    <div class="slds-theme_default">
        <div class="content-wrapper">
            <span> {! v.query }</span>
        </div>

        <div class="slds-modal__footer actions-wrapper">
            <button class="slds-button slds-button--neutral" onclick="{!c.handleCancel}">Cancel</button>
            <button class="slds-button slds-button--brand" onclick="{!c.handleSubmit}">Submit</button>
        </div>

        <aura:if isTrue="{! v.isWorking }">
            <lightning:spinner variant="brand" alternativeText="Processing" style="background: transparent" />
        </aura:if>
    </div>
</aura:componen

Apex Controller Classes

Our Aura component is ready, let's go ahead and implement our Apex controller. In our example, the job of the controller is straightforward; creates a Bulk Action Job and starts an Apex batch. To get the number of records to process, we just replace the Id with Count().

The batch class track the progress of the job and keep track of the occurred errors. At the end of the batch, we close the job.

When a job is closed, the monitor is notified and the toast message is displayed to the user.

public with sharing class TestBulkActionController {
    @AuraEnabled
    public static Id submitBulkAction(
        String gridLabel,
        String gridName,
        String actionLabel,
        String actionName,
        String query,
        String url
    ) {
        String countQuery = query.replaceAll('Select Id ', 'Select count()');

        //Submit the job to the action manager
        Id jobId = gmpkg.BulkActionManager.createJob(
            new gmpkg.BulkActionManager.BulkActionRequest(
                gridLabel,
                gridName,
                actionLabel,
                actionName,
                query,
                url,
                database.countQuery(countQuery)
            )
        );

        //Start the batch to process all the opportunities
        Database.executeBatch(new TestBulkActionBatch(jobId, query));
        return jobId;
    }
}

Bulk Action Configuration

Our Aura component and Apex Classes are ready for use. Let's go ahead and configure the grid action as below:

[
    {
        "name": "Move",
        "label": "Move",
        "bulkAction": true,
        "confirmationRequired": true,
        "component": "c:TestBulkActionComponent"
    }
]

To trigger a Bulk Action, bulkAction flag should be set to true. If not the action will be considered as synchronous action and the query will not be passed to your component.

If confirmationRequired is set to true, the user will be asked to select the scope of the action. It could be either the selected records or the whole filter scope. See the screenshot below.

Source Code

The full source code of this example is available here 👇

https://github.com/GridMate/gridmate-examples/tree/main

Last updated