2

I'm trying to use simple apex class and simple controller like a test. But can't upload ContentVersion. What is wrong here?

handleFileSelected: function(component, event, helper) {
    let files = event.getParam("files");
    let file = files[0];

    let reader = new FileReader();                
    reader.onload = function (e) {

        let targRes =  e.target.result;
        let action = component.get("c.save");
        action.setParams({
            firstPublishLocationId : 'a010E000004PRC3QAO',  //real Id
            versionData : targRes
        });
        $A.enqueueAction(action);
    }
    reader.readAsDataURL(file);           
},

apex:

@AuraEnabled
    public static void save(String firstPublishLocationId Blob versionData){ 
        ContentVersion currentContentVersion = new ContentVersion(
            Title = 'test',
            PathOnClient = 'test',
            VersionData = versionData,
            FirstPublishLocationId = firstPublishLocationId
        ); 
        insert currentContentVersion;
    }   
  • 2
    Your Lightning parameters do not match your Apex method's parameters. Does this reflect real code, or is this poorly anonymized? What specific error are you receiving? – David Reed Jan 24 at 14:06
  • It's a test code, like I say. No errors. I just don't get a cv like related with my record. And don't know, how to make it right with lightning – MichaelLev19 Jan 24 at 14:16
  • Right now, your Lightning controller is not populating firstPublishLocationId, and your Apex controller has a syntax error. – David Reed Jan 24 at 14:17
  • Sorry. I changed it. But still the same. – MichaelLev19 Jan 24 at 14:18
2

This FileUpload Component might work for you:

 <c:FileUpload parentId="" label="" />

Where parentId is the record the file will be attached to.

Component

<aura:component controller="FileUploadController">
    <aura:attribute name="parentId" type="Id" />
    <aura:attribute name="label" type="String" />
    <aura:attribute name="uploading" type="Boolean" default="false" />
    <aura:handler event="aura:waiting" action="{!c.waiting}" />
    <aura:handler event="aura:doneWaiting" action="{!c.doneWaiting}" />
    <aura:if isTrue="{!v.uploading}">
        <lightning:spinner alternativeText="Loading" size="large" />
    </aura:if>
    <div>
        <div class="slds-form-element">
            <span class="slds-form-element__label" id="file-selector-primary-label">{! v.label }</span>
            <div class="slds-form-element__control">
                <div class="slds-file-selector slds-file-selector_files">
                    <div class="slds-file-selector__dropzone">

                        <input aura:id="file" class="slds-file-selector__input slds-assistive-text" type="file" id="file-upload-input-01"
                            aria-labelledby="file-selector-primary-label file-selector-secondary-label" />
                        <label class="slds-file-selector__body" for="file-upload-input-01" id="file-selector-secondary-label">
                            <span class="slds-file-selector__button slds-button slds-button_neutral">
                                <lightning:icon iconName="utility:upload" size="xx-small" alternativeText="upload" />Upload
                                Files</span>
                            <span class="slds-file-selector__text slds-medium-show">or Drop Files</span>
                            <span>
                                <ui:button label="Upload" press="{!c.save}" />
                            </span>
                        </label>
                    </div>
                </div>
            </div>
        </div>
    </div>
</aura:component>

JavaScript Controller

({
    save: function (component, event, helper) {
        helper.save(component);
    },
    waiting: function (component, event, helper) {
        component.set("v.uploading", true);
    },
    doneWaiting: function (component, event, helper) {
        component.set("v.uploading", false);
    }
})

JavaScript Helper

({
    MAX_FILE_SIZE: 4500000, /* 6 000 000 * 3/4 to account for base64 */
    CHUNK_SIZE: 950000, /* 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) {
        console.log('uploadChunk');
        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) {

            console.log('uploadChunk: Callback');
            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);
            } else {
                console.log('uploadChunk: done');
                self.showToast('Upload Complete', 'You file has successfully uploaded, please upload another now.', 'success', null);
            }
        });

        $A.getCallback(function () {
            $A.enqueueAction(action);
        })();
    },
    showToast: function (title, message, type, icon) {
        var toastEvent = $A.get("e.force:showToast");
        toastEvent.setParams({
            title: title,
            message: message,
            duration: '2000',
            key: icon,
            type: type,
            mode: 'dismissible'
        });
        toastEvent.fire();
    },
})

Apex Controller

public without sharing class FileUploadController {

    @AuraEnabled
    public static Id saveTheFile(Id parentId, String fileName, String base64Data, String contentType) { 
        base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8');
        ContentVersion contentVersion = new ContentVersion(
            versionData = EncodingUtil.base64Decode(base64Data),
            title = fileName,
            pathOnClient =  '/' + fileName,
            FirstPublishLocationId = parentId);
        insert contentVersion; 
        return contentVersion.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');
        ContentVersion contentVersion = [
            SELECT Id, versionData
            FROM ContentVersion
            WHERE Id = :fileId
        ];
        String existingBody = EncodingUtil.base64Encode(contentVersion.versionData);
        contentVersion.versionData = EncodingUtil.base64Decode(existingBody + base64Data); 
        update contentVersion;   
    }
}

CSS

.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;
}
  • 1
    Can you add relevant code bits? Link only answers generally gets downvoted and marked as low quality – Pranay Jaiswal Jan 24 at 14:40
  • @PranayJaiswal added – Robs Jan 24 at 15:20
  • 1
    Thanks Robs. +1 – Pranay Jaiswal Jan 24 at 15:21

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.