1

I am trying to create a file upload functionality in aura:iteration. For every record in the iteration there would be functionality to attach files and would show in Notes & Attachment section.

Code for that is

1.Component

<div class="slds-form-element">
    <div aura:id = "uploadBtn" class="slds-form-element__control">
        <div class="slds-file-selector slds-file-selector_files">
            <div class="slds-file-selector__dropzone">
                <input type="file" aura:id="fileId" class="slds-file-selector__input slds-assistive-text" id="file-upload-input-01" aria-describedby="file-selector-id" multiple=""/>
                <label class="slds-file-selector__body" for="file-upload-input-01">
                    <span class="slds-file-selector__button slds-button slds-button_neutral">
                        <lightning:icon class="uploadIcon" iconName="utility:upload" size="xx-small" alternativeText="Icon"/>Attach File&nbsp;&nbsp;&nbsp;&nbsp;</span>
                </label>
            </div>
        </div>
    </div>
    <div aura:id = "fileNameDiv" class = "slds-form-element__control slds-hide">
        <ui:outputText aura:id="fileName"/>
    </div>
    <div lass="slds-form-element__control">
        <lightning:button aura:id="attachBtn" label="Upload Files" iconName="utility:attach" iconPosition="left" onclick="{!c.save}" />
    </div>
</div>

2.Controller

save : function(component, event, helper) {
        helper.save(component,event);
        //console.log(component.get("v.parentId"));
    },

3. Helper

save : function(component,event) {
    var self = this;
    var saveElement = event.getSource();
    var index = self.getClickedIndex(component,saveElement);
    console.log('index is'+index);
    if(index!=-1){
        var outlets = component.get("v.outlets");
        var parentId = outlets[index].Id;
        console.log(parentId);
        //making index as 0
        var attachIndex= 0;
        var fileInput = component.find("fileId")[attachIndex].getElement();

        var file = fileInput.files[attachIndex];
        console.log('File is '+file);

        if(file != undefined){
            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 hidebtn = component.find("uploadBtn")[index];
            $A.util.toggleClass(hidebtn, "slds-hide");
            var showFileName = component.find("fileNameDiv")[index];
            var fileNameText = component.find("fileName")[index].set("v.value",file.name);
            $A.util.toggleClass(showFileName, "slds-hide");

            var fr = new FileReader();
            var self = this;

            //console.log(file.size);

            fr.onload = $A.getCallback(function() {
                var fileContents = fr.result;
                var base64Mark = 'base64,';
                var dataStart = fileContents.indexOf(base64Mark) + base64Mark.length;

                fileContents = fileContents.substring(dataStart);

                self.upload(component, file, fileContents, parentId);
            });

            fr.readAsDataURL(file);
        } else {
            alert('File not uploaded');
        }
    }
},

upload: function(component, file, fileContents, parentId) {
    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, '', parentId);   
},     

uploadChunk : function(component, file, fileContents, fromPos, toPos, attachId, parentRecordId) {
    var action = component.get("c.saveTheChunk"); 
    var chunk = fileContents.substring(fromPos, toPos);

    action.setParams({
        parentId: parentRecordId,
        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.enqueueAction(action); 
},

//This function is used to get the index of the clicked button for saving the attachment
getClickedIndex: function(component, btnElement) {
    var noOfOutlets = component.get("v.outlets").length;

    for(var i=0; i<noOfOutlets; i++){
        if(component.find("attachBtn")[i]==btnElement) return i;
    }
    return -1;
},

The problem is that whenever I click on upload for any row it would select only for first row and after selecting the file first row button would be highlighted and if I click on upload button for any row other than the first row it would show that file is undefined. If I click on upload button on the first row it would upload the file, regardless of the row for which it was selected. What could be the reason?

  • Your problem is in the controller/helper, not in the component code. There's no way we can help you with what you've given us. – sfdcfox Jun 27 '17 at 11:36
  • @sfdcfox I have added the code for controller and helper. – Abhishek Prakash Jun 28 '17 at 6:03
0

You appear to be setting the index for the file object to zero.

I think you were trying to access the first file in the files list (which would have an index of 0) but you've used it to access the array of files inputs - and you should be using the index that you got earlier for that.

Change this:

//making index as 0
var attachIndex= 0;
var fileInput = component.find("fileId")[attachIndex].getElement();
var file = fileInput.files[attachIndex];

To this:

//see we are using the index you previously found
var fileInput = component.find("fileId")[index].getElement();
var file = fileInput.files[attachIndex];  //you could just use 0 here
  • The code that I have provided is working because of using 0 as attachIndex (file is always selected for 0th row). There are two problems with this approach 1. When the file is selected focus shifts to 0th row. 2. In this case I have written the code inside the component, so i can access the 0th row as aura id is converted to a list. But, I want to convert it to a reusable component and I cannot access the files from 0th row, even if somehow I was able to access the file, the problem of focus will remain. – Abhishek Prakash Jun 28 '17 at 6:11
-1

I found the problem, It was due to the use of id field which is same for all the rows of aura:iteration.

So, changing the code to something like

<input type="file" aura:id="fileId" class="slds-file-selector__input slds-assistive-text" id="{!'file-upload-input-'+index}" aria-describedby="file-selector-id" multiple=""/>
<label class="slds-file-selector__body" for="{!'file-upload-input-'+index}">

instead of the original

<input type="file" aura:id="fileId" class="slds-file-selector__input slds-assistive-text" id="file-upload-input-01" aria-describedby="file-selector-id" multiple=""/>
<label class="slds-file-selector__body" for="file-upload-input-01">

works for me.

Thanks everyone for the help!

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.