LWC method to convert selected file content to base64 String and call the apex method for uploading as related Notes and Attachment on a particular record
myComponent.js
const toBase64 = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
async handleDeviceFileSelection(event) {
const file = event.target.files[0];
const fileName = file.name;
const base64String = await toBase64(file);
const encodedString = base64String.split('base64,')[1];
saveAttachment({parentId: parentId, file: encodedString, name: fileName}).then(() => {
// do something based on the response
}).catch((err) => {
showError(this, err)
})
}
Apex Controller
@AuraEnabled
public static void saveAttachment(String parentId, String file, String name){
Attachment attachment = new Attachment();
attachment.Body = EncodingUtil.base64Decode(file);
attachment.Name = String.valueOf(name);
attachment.ParentId = parentId;
if (Schema.sObjectType.Attachment.isCreateable()) {
insert attachment;
}
}
Note: I can't use lightning-file-upload as I have to handle few things before upload and also mine is lightning out app, so anyway lightning-file-upload is not compatible with the application. Also I guess upload with Connection.js and Jsforce does not with lightning web components!!.
This throws heap size limit error in apex even for file of 5MB. Sometimes it throw
"[AuraClientInputException from server] Unexpected request input. Expected input format: "Max message parameter length is 4194304 characters."."
Thanks in Advance for any help with this issue
Best Answer
It's pretty difficult (read: basically impossible) to work around the heap limit in Apex here.
No matter what approach you try to take, you'll always run into the issue of needing to have the data in-memory (i.e. on the heap) to be able to save the data. On other platforms (I'm thinking along the lines of Apache + PHP) you'd be able to utilize less memory (at the cost of needing to make more requests) by chunking your data and then reassembling it on the server. I don't think there's much benefit to that approach on the Salesforce platform though.
Your best bet here is probably to use the REST API that Salesforce provides. There is documentation specifically for inserting/updating blob data
In a nutshell, instead of calling an Apex method, you'll make an http call from your component to an endpoint like
https://yourInstance.salesforce.com/services/data/v23.0/sobjects/Document/
(and set various headers, set the boundary string, and include your target data in the request too. The documentation goes into more depth).