0

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

  • The reason stringify gives you the error because JS is case sensitive. You should use JSON.stringify(result) instead of json.stringify(result). – sanket kumar Jul 3 at 14:58
  • @sanketkumar Thanks. But I am getting the entire object instead if separate field value if I use this.jobStatus = getFieldValue(JSON.stringyfy(result), JOB_STATUS); -- it should return Job Status only but getting object instead. – Dhananjay Patil Jul 3 at 15:10
0

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.

| improve this answer | |
  • @sfdxfox I have already put a check in my apex class that IF existing job is in Progress, do not call same batch again. I am not able to retrieve variable bulkBatchId in getBatchJobStatus() even after declaring it public and if Batch Job is in progress. – Dhananjay Patil Jul 3 at 15:14
  • when you mentioned accessing field directly, u meant I don't need to use import tab to import field in JS? – Dhananjay Patil Jul 3 at 15:17
  • 1
    @DhananjayPatil The import statements are useful to link the field to the code to prevent people from accidentally breaking your code by deleting the field, but the getFieldValue method only works for UI-API record data, which would be via getRecord. If you used getRecord, you wouldn't need the getBatchJobStatus method, as you could get the data directly from the UI-API. – sfdcfox Jul 3 at 15:19
  • Tried to use getrecord where I am passing batch job Id but it’s not giving a result. It is going to error instead of data. Could u please share sample code or any reference? – Dhananjay Patil Jul 3 at 16:17
  • @DhananjayPatil Actually, looks like AsyncApexJob isn't supported by getRecord. Still, you should return the job Id and use that to query the current job progress. – sfdcfox Jul 3 at 16:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.