-1

I have component inside visualforce page. it working in lightning out. There is lightning:input file in the component. When I upload files larger than 1.7 MB server throws error: Apex heap size too large: 7954798. I know enabled heap size is 6 MB, but why I receive this error with files for example 2 MB size? My JS helper:

({
    MAX_FILE_SIZE: 4718592, //Max file size 4.5 MB
    CHUNK_SIZE: 750000,      //Chunk Max size 750Kb

    init: function(component, event, helper) {

        const action = component.get('c.getWorkOrder');
        action.setParams({
            woId: component.get('v.workOrderId'),
        });

        action.setCallback(this, (response) => {
        const respState = response.getState();
            if (respState === 'SUCCESS') {
                const workOrder = response.getReturnValue();
                component.set('v.workOrder', workOrder);

                let isCompleted = false;
                if (typeof (workOrder.Site_Survey__c) !== 'undefined' && workOrder.Site_Survey__r.Completed__c) {
                    isCompleted = true;
                }
                component.set('v.surveyCompleted', isCompleted);

                if (!isCompleted) {
                    const flow = component.find("flowData");
                    const inputVariables = [
                    {
                        name : 'recordId',
                        type : 'String',
                        value : component.get('v.workOrderId'),
                    }
                    ];
                    flow.startFlow("Site_Survey_Form", inputVariables);
                }
            }
        });

        $A.enqueueAction(action);
    },

    statusChangeHelper: function(component, event) {
        let status = event.getParam('status');
        component.set('v.flowStatus', status);

        let currentStage = event.getParam('currentStage');
        let currentStageLabel = JSON.parse(JSON.stringify(currentStage.label));
        component.set('v.currentStage', currentStageLabel);

        console.log('current stage: ' + currentStageLabel);

        if(currentStageLabel == 'Finish_Stage') {
            component.set('v.surveyCompleted', true);
        }        
    },

    fileChange: function (component, event) {
        let fileName = '';
        let files = event.getSource().get("v.files");

        if (files.length > 0) {
            for(let i = 0; i < files.length; i++) {
                if (files[i].size > this.MAX_FILE_SIZE) {
                    fileName =  'Alert : File size cannot exceed ' + this.MAX_FILE_SIZE / 1048576 + ' Mb.\n' + 
                                    ' Selected file ' + '\"' + files[i].name + '\"' + ' size: ' + 
                                    Math.round((files[i].size / 1048576) * 100) / 100 + 'Mb';
                    break;
                } else {
                    fileName += files[i].name;
                    if(i < files.length - 1) fileName += ', ';
                }

            }
        }

        if(fileName == '') {
            component.set("v." + event.getSource().get('v.name'), 'No File Selected..');
        } else {
            component.set("v." + event.getSource().get('v.name'), fileName);
        }
    },

    uploadHelper: function(component, event) {
        let self = this;
        let fileInput = [];

        if (component.find("fileId1") && component.find("fileId1").get("v.files")) {
            let fileList = component.find("fileId1").get("v.files");
            Array.prototype.forEach.call(fileList, file => {
                fileInput.push(file);
                console.log('file.size:' + file.size);
            });
        }

        fileInput.forEach((f) => {
            let objFileReader = new FileReader();

            objFileReader.onload = $A.getCallback(() => {
                let fileContents = objFileReader.result;
                var base64 = 'base64,';
                var dataStart = fileContents.indexOf(base64) + base64.length;

                fileContents = fileContents.substring(dataStart);

                self.uploadProcess(component, f, fileContents);
            });

            objFileReader.readAsDataURL(f);
        });      
    },

    uploadProcess: function(component, file, fileContents) {
        // set a default size or startpostiton as 0
        var startPosition = 0;
        // calculate the end size or endPostion using Math.min() function which is return the min. value
        var endPosition = Math.min(fileContents.length, startPosition + this.CHUNK_SIZE);
        // start with the initial chunk, and set the attachId(last parameter)is null in begin
        this.uploadInChunk(component, file, fileContents, startPosition, endPosition, '');
    },

    uploadInChunk: function(component, file, fileContents, startPosition, endPosition, attachId) {
        // call the apex method 'saveChunk'
        var getchunk = fileContents.substring(startPosition, endPosition);
        console.log('start:' + startPosition + ', end:' + endPosition);
        var action = component.get("c.saveChunk");
        action.setParams({
            parentId: component.get("v.workOrder").Site_Survey__c,
            fileName: file.name,
            base64Data: encodeURIComponent(getchunk),
            contentType: file.type,
            fileId: attachId
        });

        // set call back
        action.setCallback(this, function(response) {
            // store the response / Attachment Id
            attachId = response.getReturnValue();
            var state = response.getState();
            if (state === "SUCCESS") {
                // update the start position with end postion
                startPosition = endPosition;
                endPosition = Math.min(fileContents.length, startPosition + this.CHUNK_SIZE);
                // check if the start postion is still less then end postion
                // then call again 'uploadInChunk' method ,
                // else, diaply alert msg and hide the loading spinner
                if (startPosition < endPosition) {
                    this.uploadInChunk(component, file, fileContents, startPosition, endPosition, attachId);
                } else {
                    //alert('your File is uploaded successfully');
                    component.set("v.showLoadingSpinner", false);
                }
            // handel the response errors
            } else if (state === "INCOMPLETE") {
                alert("From server: " + response.getReturnValue());
            } else if (state === "ERROR") {
                var errors = response.getError();
                if (errors) {
                    if (errors[0] && errors[0].message) {
                        console.log("Error message: " + errors[0].message);
                    }
                } else {
                console.log("Unknown error");
                }
            }
        });
        // enqueue the action
        $A.enqueueAction(action);
    }
})

My Apex Controller:

@AuraEnabled
    public static Id saveChunk(Id parentId, String fileName, String base64Data, String contentType, String fileId) {
        // check if fileId id ''(Always blank in first chunk), then call the saveTheFile method,
        //  which is save the check data and return the attachemnt Id after insert,
        //  next time (in else) we are call the appentTOFile() method
        //   for update the attachment with reamins chunks
        if (fileId == '') {
            fileId = saveTheFile(parentId, fileName, base64Data, contentType);
        } else {
            appendToFile(fileId, base64Data);
        }

        return Id.valueOf(fileId);
    }

    public static Id saveTheFile(Id parentId, String fileName, String base64Data, String contentType) {
        base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8');

        Attachment oAttachment = new Attachment();
        oAttachment.parentId = parentId;

        oAttachment.Body = EncodingUtil.base64Decode(base64Data);
        oAttachment.Name = fileName;
        oAttachment.ContentType = contentType;

        insert oAttachment;

        return oAttachment.Id;
    }

    private static void appendToFile(Id fileId, String base64Data) {
        base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8');

        Attachment a = [
                SELECT Id, Body
                FROM Attachment
                WHERE Id =: fileId
        ];

        String existingBody = EncodingUtil.base64Encode(a.Body);

        a.Body = EncodingUtil.base64Decode(existingBody + base64Data);

        update a;
    }

1 Answer 1

0

This was previously answered, it seems that it was cap to 1MB. The previous answer mentions lightning:fileUpload for larger files or chunking the file.

2
  • Yes I use chunks, fileUpload not working in lightning out Jun 11, 2020 at 9:03
  • 1
    Then I believe would be good to add this into your question and explain how the chunking is performed. That may shed light for me or others to help you further. Jun 11, 2020 at 9:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .