lightning

File Upload Lightning Component

The Lightning Component Framework was introduced at Dreamforce ’14 as part of the collection of tools that represent a significant upgrade to the Salesforce1 Platform.  Currently the components can be used in the Salesforce1 mobile app and standalone apps.  In this article I detail a custom Lightning Component that allows a user to upload a file to Salesforce as a related Attachment record on a specified sObject record.  The article starts off by showing a simple component that works for smaller files (< 1MB) and then builds on that with a component that works on larger files (~4.5 MB).

Component Summary

The component consists of the following:

  • fileUpload.cmp – The component definition – Basic markup and attribute definitions
  • fileUploadController.js – The controller – Hands off processing to helper
  • fileUploadHelper.js – The helper – Sets up call to Apex controller and handles result
  • fileUpload.css – The styles – Basic styles related to the spinner for uploading
  • FileController.cls – The ApexController – Creates the Attachment

The code of fileUpload.cmp, fileUploadHelper.js, and FileController.cls are shown in this article; however, all of the code is available on GitHub.

The component has some very, very basic styling since that is not the focus of this article.  It first displays with a button to select a file and a save button. While saving it displays the spinner.

upload selection
Select a file
file uploading
File uploading

Component Code

The component markup is as follows:

The component accepts the Id of the related object as an attribute, contains a file input, save button, and spinner that is displayed when the file is being uploaded.

Note the use of the “aura:id” on the file input.  Using “aura:id” is necessary to be able to use the component.find(“file”) method in the helper JavaScript to locate the file input.  What’s very powerful here is that the input element is itself translated into a component by the framework and gets all of the benefits of being a component along with it.

The aura:waiting and aura:doneWaiting are events defined in the component markup and are fired by the framework when the component has invoked an Action that calls to the server and when the response is received, respectively.  The controller actions that they invoke simply hide or show the spinner div by applying CSS.

Uploading

The controller’s save method is called when the save button is pressed.  It delegates to the helper’s save method to handle the work.

The helper’s save function gets a reference to the action that represents the Apex controller’s saveTheFile method.  Note that the name of the method (saveTheFile) on the Apex controller is different from the JavaScript controller (save).  If they were both named “save”, then the call to component.get(“c.save”) would evaluate to a reference to the JavaScript’s save action, that would get called and infinite loop would result.  Users are protected against the infinite loop and the result is actually an error overlay with a message “finishFiring has not completed after 15 loops”.

The save function reads the file using a FileReader and its readAsDataURL method.  The readAsDataUrl method reads the file contents into a blob containing a data: URL.  The maximum String size that can be sent to an @AuraEnabled Apex controller method appears to be 1,000,000, which is consistent with @Remote method limits.  The MAX_FILE_SIZE takes into account the size increase due to Base64 encoding.  It is necessary to URL encode the file contents prior to sending them to the server.  This is done with the encodeURIComponent function.

The Apex controller simply takes the input, saves it in a Attachment and returns an Attachment Id.  Since the data was URL encoded on the client the method decodes it with the EncodingUtil.urlDecode method.

Larger Files

The above is a great start, but is limited by the small file size.  Derek Lansing blogged, in this article, about a good way to handle larger files when uploading using @Remote methods that increases the allowed file size to about 4.3 MBs.  That approach reads the file, and then sends it to the @Remote method in chunks that are under the limits.  The Apex controller method then selects the Attachment out of the database on each successive iteration and updates its body.

Adapting the Lightning component to chunk the files, results in the following helper. Note that the component and the controller JS remain unchanged.

In this version the Attachment’s Id is an additional parameter that is sent to the Apex controller.  On the initial invocation the Attachment’s Id is not set.  It is returned by the Apex controller and then retrieved in the helper with the a.getReturnValue() method call.

On successive calls the Apex controller performs an update.  Below is the updated Apex controller.

More

In this article I detailed a simple Lightning component for uploading smaller files and expanded on it with a slightly more complex component to support larger files.  To learn more about Lightning see Salesforce1 Lightning Developer page for a list of resources.

All of the code is available on GitHub.