Skip to content

Instantly share code, notes, and snippets.

@peterknolle
Last active January 30, 2023 20:40
Show Gist options
  • Save peterknolle/bb4b7ac63f67f66c32b0 to your computer and use it in GitHub Desktop.
Save peterknolle/bb4b7ac63f67f66c32b0 to your computer and use it in GitHub Desktop.
Lightning File Upload Component
public class FileController {
@AuraEnabled
public static Id saveTheFile(Id parentId, String fileName, String base64Data, String contentType) {
base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8');
Attachment a = new Attachment();
a.parentId = parentId;
a.Body = EncodingUtil.base64Decode(base64Data);
a.Name = fileName;
a.ContentType = contentType;
insert a;
return a.Id;
}
@AuraEnabled
public static Id saveTheChunk(Id parentId, String fileName, String base64Data, String contentType, String fileId) {
if (fileId == '') {
fileId = saveTheFile(parentId, fileName, base64Data, contentType);
} else {
appendToFile(fileId, base64Data);
}
return Id.valueOf(fileId);
}
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;
}
}
<!-- fileUpload2.cmp is identical -->
<aura:component controller="paura.FileController">
<aura:attribute name="parentId" type="Id"/>
<aura:handler event="aura:waiting" action="{!c.waiting}"/>
<aura:handler event="aura:doneWaiting" action="{!c.doneWaiting}"/>
<div class="container">
<input type="file" class="file" aura:id="file" />
<ui:button label="Save" press="{!c.save}"/>
<div aura:id="uploading" class="notUploading">
<img src="/resource/paura__images/loading-gray.gif" alt="uploading" class="small-spinner" /> Uploading...
</div>
</div>
</aura:component>
/* fileUpload2.css is identical */
.THIS .notUploading {
visibility: hidden;
}
.THIS .uploading {
visibility: visible;
display: inline-block;
margin-top: 10px;
}
.THIS .small-spinner {
height: 20px;
width: 20px;
}
.THIS .file {
margin-bottom: 5px;
display: block;
}
/* fileUploadController2.js is identical */
({
save : function(component, event, helper) {
helper.save(component);
},
waiting: function(component, event, helper) {
$A.util.addClass(component.find("uploading").getElement(), "uploading");
$A.util.removeClass(component.find("uploading").getElement(), "notUploading");
},
doneWaiting: function(component, event, helper) {
$A.util.removeClass(component.find("uploading").getElement(), "uploading");
$A.util.addClass(component.find("uploading").getElement(), "notUploading");
}
})
({
MAX_FILE_SIZE: 750 000, /* 1 000 000 * 3/4 to account for base64 */
save : function(component) {
var fileInput = component.find("file").getElement();
var file = fileInput.files[0];
if (file.size > this.MAX_FILE_SIZE) {
alert('File size cannot exceed ' + this.MAX_FILE_SIZE + ' bytes.\n' +
'Selected file size: ' + file.size);
return;
}
var fr = new FileReader();
var self = this;
fr.onload = function() {
var fileContents = fr.result;
var base64Mark = 'base64,';
var dataStart = fileContents.indexOf(base64Mark) + base64Mark.length;
fileContents = fileContents.substring(dataStart);
self.upload(component, file, fileContents);
};
fr.readAsDataURL(file);
},
upload: function(component, file, fileContents) {
var action = component.get("c.saveTheFile");
action.setParams({
parentId: component.get("v.parentId"),
fileName: file.name,
base64Data: encodeURIComponent(fileContents),
contentType: file.type
});
action.setCallback(this, function(a) {
attachId = a.getReturnValue();
console.log(attachId);
});
$A.run(function() {
$A.enqueueAction(action);
});
}
})
({
MAX_FILE_SIZE: 4 500 000, /* 6 000 000 * 3/4 to account for base64 */
CHUNK_SIZE: 950 000, /* Use a multiple of 4 */
save : function(component) {
var fileInput = component.find("file").getElement();
var file = fileInput.files[0];
if (file.size > this.MAX_FILE_SIZE) {
alert('File size cannot exceed ' + this.MAX_FILE_SIZE + ' bytes.\n' +
'Selected file size: ' + file.size);
return;
}
var fr = new FileReader();
var self = this;
fr.onload = function() {
var fileContents = fr.result;
var base64Mark = 'base64,';
var dataStart = fileContents.indexOf(base64Mark) + base64Mark.length;
fileContents = fileContents.substring(dataStart);
self.upload(component, file, fileContents);
};
fr.readAsDataURL(file);
},
upload: function(component, file, fileContents) {
var fromPos = 0;
var toPos = Math.min(fileContents.length, fromPos + this.CHUNK_SIZE);
// start with the initial chunk
this.uploadChunk(component, file, fileContents, fromPos, toPos, '');
},
uploadChunk : function(component, file, fileContents, fromPos, toPos, attachId) {
var action = component.get("c.saveTheChunk");
var chunk = fileContents.substring(fromPos, toPos);
action.setParams({
parentId: component.get("v.parentId"),
fileName: file.name,
base64Data: encodeURIComponent(chunk),
contentType: file.type,
fileId: attachId
});
var self = this;
action.setCallback(this, function(a) {
attachId = a.getReturnValue();
fromPos = toPos;
toPos = Math.min(fileContents.length, fromPos + self.CHUNK_SIZE);
if (fromPos < toPos) {
self.uploadChunk(component, file, fileContents, fromPos, toPos, attachId);
}
});
$A.run(function() {
$A.enqueueAction(action);
});
}
})
<!-- This is a simple app that shows how the component can be used.
The Id could be passed in via URL or some other mechanism.
This is just for testing.
-->
<aura:application>
<div class="container">
<!--<paura:fileUpload parentId="0013020s006DqaI"/>-->
<paura:fileUpload2 parentId="0013020s006DqaI"/>
</div>
</aura:application>
@RanaForam
Copy link

Hi @peterknolle @Satya738

How can we modify the code to upload a 10 MB file ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment