[SalesForce] How to display Batch Record Process Count on Progress Bar Indicator in LWC

I am currently working on functionality where I am assigning Bulk Records Ownership to new user. For this, I have designed LWC and which calls helper class.
and the helper class call a batch class to perform bulk update operation(If record counts are more than 50).

When I assign records in bulk, I want to display progress bar where it should display counts of records processing out of Total Records from a batch and once batch is completed, it should display the status as completed. If certain records fails, then it should display number of processed records.

Purpose : In LWC, when I assign records to new User, it calls wire method and refresh the record list. Since I am performing Asynchronous operation(Bulk) here,I am not able to control sequence of execution here.Meaning when batch class starts before batch class completes, wire method gets called and refresh the list due to which I am not able to see updated count in data-table(only in case of Asynchronous).

What I what to achieve : I want to call wire function which refresh the record list only when my batch class process is completed that's why I am showing progress bar here.

Below is part LWC that I have designed for displaying Progress Bar:

<lightning-card class="slds-theme_shade" title="Batch Class Result" icon-name="custom:custom61" variant="base">
    <lightning-card title="Progress Bar">
        <template if:true={isBulk}>
            <div style="margin-left: 2%;">
                <lightning-progress-bar value={progress} variant="circular">
                </lightning-progress-bar>
            </div>
            <div class="slds-text-align--center slds-text-title" style="color:forestgreen;">
                {processStatus}
            </div>
        </template>
    </lightning-card>

Below is JS File where I am trying to fetch field value of NumberOfErrors,JobItemsProcessed,TotalJobItems,Status of AsyncApexJob object:

import {
    LightningElement,
    wire,
    track,
    api
} from 'lwc';
import {
    getRecord,
    getFieldValue
} from 'lightning/uiRecordApi';
import {
    ShowToastEvent
} from 'lightning/platformShowToastEvent';
import assignRecordsToNewOwner from '@salesforce/apex/MassReassignHelper.assignRecordsToNewOwner';
import getBatchJobStatus from '@salesforce/apex/MassReassignHelper.getBatchJobStatus'
import ERROR_RECORDS from '@salesforce/schema/AsyncApexJob.NumberOfErrors';
import ITEMS_PROCESSED from '@salesforce/schema/AsyncApexJob.JobItemsProcessed';
import TOTAL_RECORDS from '@salesforce/schema/AsyncApexJob.TotalJobItems';
import JOB_STATUS from '@salesforce/schema/AsyncApexJob.Status';
import {
    refreshApex
} from '@salesforce/apex';
export default class MassReassignSObjectParent extends LightningElement {
    label = {
        HeaderText,
        SearchBlockTitle
    };
    _wiredResult;
    @track progress = 0;
    @track isBulk = false;
    @track processStatus = 'In Progress';
    totalRec = '';
    recProcessed = '';
    errRec = '';
    jobStatus = '';

    handleBulkAssign(event) {
        this.isBulk = true;

        if (this.newOwner != '') {
            this.assignRecords = this.selection;
            if (this.assignRecords.length > 50) {
            //calling controller class method which assign records in Bulk by calling batch class
                assignRecordsToNewOwner({
                        sObjRecords: this.assignRecords,
                        objType: this.objType,
                        newOwner: this.newOwner
                    })
                    .then(result => {
                        console.log('Records are assigned successfully:' + result);

                    })
                    .catch(error => {
                        console.log('Exception Occured:' + error);
                        //this.error = error;
                        const evt = new ShowToastEvent({
                            title: error,
                            message: 'Exception Occured While Assigning Bulk Records and Error is:' + this.error,
                            variant: 'error',
                            mode: 'dismissable'
                        });
                        this.dispatchEvent(evt);
                    });

            }

        }
    }
    renderedCallback() {
    //Purpose: TO Check Batch Job status in certain time interval and fetch the count and display it in Progress bar.
        console.log('Calling renderedCallback:' + this.isBulk);
        if (this.isBulk == true) {
            this._interval = setInterval(() => {
                getBatchJobStatus({})
                    .then(result => {
                        console.log('Calling Batch Statu1:' + result);
                        //var resu = json.stringify(result);//If I try to use stringify, it throws an error on UI.because results I am getting here is [object][object]
                        console.log('Status is:' + getFieldValue(record, JOB_STATUS));
                        this.jobStatus = getFieldValue(result, JOB_STATUS);
                        console.log('Total Records:' + this.jobStatus);
                        this.totalRec = getFieldValue(result, TOTAL_RECORDS);
                        console.log('Total Records:' + this.totalRec);
                        this.recProcessed = getFieldValue(result, ITEMS_PROCESSED);
                        console.log('Records Processed:' + this.recProcessed);
                        this.errRec = getFieldValue(result, ERROR_RECORDS);
                        console.log('Total Records:' + this.errRec);
                    });
                this.progress = parseInt(this.progress) + this.recProcessed;
                console.log('Progress is:' + this.progress);
                this.processStatus = 'Processing => ' + this.progress + '/' + this.totalRec;
                if (this.progress === this.totalRec) {
                    clearInterval(this._interval);
                    this.processStatus = 'Completed';
                }
            }, 5000);
            if (this.processStatus == 'Completed') {
                console.log('Refreshing Wire Status');
                //will call my wire method to refresh the results once batch process completes
                return refreshApex(this._wiredResult);
            }

        }


    }

}

Below is Controller class:

public with sharing class MassReassignHelper {
public static Id bulkBatchId;
    @AuraEnabled
    //public static void assignRecordsToNewOwner(List < sObject > sObjRecords, String objType, String newOwner) {
    public static boolean assignRecordsToNewOwner(List < Id > sObjRecords, String objType, String newOwner) {
        system.debug('calling assignRecordsToNewOwner:' + sObjRecords);
        system.debug('Object Type:' + objType);
        system.debug('new Owner is:' + newOwner);
        boolean isException = false;
        List < sObject > sObjToUpdateList = new List < sObject > ();
        if (!sObjRecords.isEmpty() && !String.isBlank(objType) && !String.isBlank(newOwner)) {
            system.debug('Assigning Records to new owner:' + sObjRecords.size());
            for (Id objId: sObjRecords) {
                Id recordId = objId;
                system.debug('Record Id is:' + recordId);
                system.debug('Assigning NEw Owner:' + newOwner);
                SObject objects = recordId.getSObjectType().newSObject(recordId);
                objects.put('OwnerId', newOwner);
                sObjToUpdateList.add(objects);
            }
            if (sObjToUpdateList.size() <= 50) { 
                system.debug('Performing Synchromous Exceution');
                try {
                    Database.update(sObjToUpdateList, false);
                } catch (Exception ex) {
                    system.debug('Exception occured');
                    isException = true;
                    throw new AuraHandledException('Exception Occured When Updating Records: ' + ex.getMessage());
                }
            } else if (sObjToUpdateList.size() > 50) {
                Id batchId = Id.valueOf(Label.Bulk_Transfer_Batch_Id);
                system.debug('Calling BulkTransferRecordsBatch Class:' + batchId);
                //check if existing job in progress
                AsyncApexJob[] job = [select Id from AsyncApexJob where Status = 'Processing'
                    AND ApexClassId =: batchId AND JobType = 'BatchApex'
                ];
                if (job.size() == 0) {
                    try {
                        system.debug('Executing Batch');
                        BulkTransferRecordsBatch bulkSObjBatch = new BulkTransferRecordsBatch(sObjToUpdateList);
                        bulkBatchId = Database.executeBatch(bulkSObjBatch, 25);
                    } catch (Exception ex) {
                        system.debug('Exception occured while calling batch');
                        isException = true;
                        throw new AuraHandledException('Exception Occured When Updating Records: ' + ex.getMessage());
                    }
                } else {
                    system.debug('Existing Batch in Progress');
                    isException = true;
                    throw new AuraHandledException('Existing Batch Class is not completed.Please wait..');
                }

            }
            if (isException) {
                return false;
            } else {
                system.debug('Returning True');
                return true;
            }
        } else {
            return false;
        }
    }
    @AuraEnabled(cacheable = true)
    public static AsyncApexJob getBatchJobStatus() {
        system.debug('Job ID is:' + bulkBatchId);
        Id classId = Id.valueOf(Label.BatchClassId);
        system.debug('Batch Class ID is:' + classId);
        AsyncApexJob jobInfo = [SELECT Status, NumberOfErrors, JobItemsProcessed, TotalJobItems FROM AsyncApexJob WHERE ApexClassId=:classId AND Status='Processing' AND JobType='BatchApex'];
        system.debug('Job Info is:' + jobInfo);
        return jobInfo;
    }
    
}

Issue: In js file, I am getting totalRec, recProcessed,errRec & jobStatus value as [Object][Object] due to which my progress bar is not working. if I try to Stringyfy then It throws an error on UI.

Can someone please help me how can fetch Batch Record count and display it in Progress Bar?

Any other approach would be helpful.

Reference:

https://www.forcetree.com/2019/11/execute-batch-apex-from-lightning.html

https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_get_field_value

Best Answer

Your main problem is that you should be returning the job Id to make sure you have the correct batch (more than one batch could be running). Second, imperative apex records return a different structure than that required for getFieldValue. Simply access the fields directly, or use a wired getRecord method.

Related Topic