1

I have created a Visualforce page using Jquery , I am uploading PDF file . However, Onafter successful uploading it is given me Error --- Failed to load PDF Document

The VF Page involved is :

<apex:page standardController="Account" extensions="FileUploadControllerSample" sidebar="false" showHeader="false">

   <style>
   .fileCount,.errorMsg{font-size:14px;width:400px;padding:10px 0;display:none;}
   .fileDetails{font-size:14px;width:400px;padding:10px 0;}
   .fileClass{
        width: 100%;
        background: none repeat scroll 0% 0% #E8FAFF;
    }
    #uploadButton {
        padding: 1px 8px !important;
        margin: 0px;
        position: absolute;
        font-size: 13px !important;
        height: 24px;
    }
    .btn-info {
        color: #FFF!important;
        background: #337ab7!important;
            border-color: #2e6da4!important;
        padding:6px 12px!important;
        font-size:15px!important;
    }
    .progressBox {
        border:1px solid #eee;
        margin:10px 0;
        padding:4px 4px;
        position: relative;
    }
    .alert {
        padding: 2px!important;
    }
    .percentComplete {
        animation: 2s linear 0s normal none infinite progress-bar-stripes;
        height: 100%;
        font-size: 12px;
        line-height: 20px;
        color: #FFF;
        text-align: center;
        background-color: #337AB7;
        box-shadow: 0px -1px 0px rgba(0, 0, 0, 0.15) inset;
        transition: width 0.6s ease 0s;
        text-align:center;
        width:0px;
        font-weight: bold;
    }
    .fileName {
        position: absolute;
        font-size: 12px;
        padding: 1px 4px;
        color: black;
        font-weight: bold;
        top: 5px;
        right: 0px;
    }
   </style>

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"/>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>

<script type="text/javascript">

        var parentId = '';
        var dropZoneID = '';
        var displaySize = '';
        var uploadable = [];
        var fileId = [];
        var uploadMarkup = '';
        var files;
        var uploadMarkup = '';
        var j$ = jQuery.noConflict();
        var i = 0;
        var mfiles;
        var upIndex = 0;
        var byteChunkArray; 
        var currentFile;
        var $upload;
        var CHUNK_SIZE = 180000; //Must be evenly divisible by 3, if not, data corruption will occur
        var VIEW_URL = '/servlet/servlet.FileDownload?file=';
        var dataIndex = '';
        var up = 0;

j$(document).ready(function(){

      j$('.fileClass').on('change', function(){
            mfiles = this.files;
            parentId = this.id;
            j$('.errorMsg').css('display','none').html('');
            for(var m=0; m < mfiles.length; m++){
                       if(mfiles[m].size < 4362185){
                        uploadable.push(mfiles[m]);
                        fileId.push(parentId);
                        displaySize = Math.floor(uploadable[up].size/1000) + 'K';
                        uploadMarkup += '<div id="upload-'+up+'" class="progressBox " data-status="pending" data-index="'+up+'">';                        
                        uploadMarkup += '<div class="percentComplete progress-bar-striped active">0%</div>';
                        uploadMarkup += '<div class="fileName">'+displaySize+'</div>';
                        uploadMarkup += '</div>';
                        j$('#container-'+parentId+' #'+parentId).after(uploadMarkup);
                        uploadMarkup = '';
                        up++;
                       }
                       else{
                          j$('.errorMsg').css('display','block').html("File size should be less then <b>4MB</b>");   
                          return false;
                       }  
            }
            this.files = null;
            j$('.fileCount').css('display','block').html("<b>"+uploadable.length+"</b> file ready to upload");
      }); 

      j$("#uploadButton").click(function(){
                up = 0;

                if( uploadable.length < 1 ){
                       j$('.errorMsg').css('display','block').html('<b>Please select file</b>');
                       return;       
                }
                else{
                    j$('.errorMsg').css('display','none').html("");
                    j$("input").attr("disabled", "disabled");
                    j$("button").attr({
                        disabled: "disabled",
                        class: "btnDisabled"
                    });                   
                    checkForUploads();
                }
       });
});

    function checkForUploads(){
        var fileCount = j$('.progressBox').length;
        if(fileCount > 0){

            //Based on index of the div, get correct file from files array
                currentFile = uploadable[upIndex];
                parentId = fileId[upIndex];
                $upload = j$('#container-'+parentId+' #upload-'+upIndex+'');
            /*Build the byteChunkArray array for the current file we are processing. This array is formatted as:
            ['0-179999','180000-359999',etc] and represents the chunks of bytes that will be uploaded individually.*/
            byteChunkArray = new Array();  

            //First check to see if file size is less than the chunk size, if so first and only chunk is entire size of file
            if(currentFile.size <= CHUNK_SIZE){
                byteChunkArray[0] = '0-' + (currentFile.size - 1);
            }else{
                //Determine how many whole byte chunks make up the file,
                var numOfFullChunks = Math.floor(currentFile.size / CHUNK_SIZE); //i.e. 1.2MB file would be 1000000 / CHUNK_SIZE
                var remainderBytes = currentFile.size % CHUNK_SIZE; // would determine remainder of 1200000 bytes that is not a full chunk
                var startByte = 0;
                var endByte = CHUNK_SIZE - 1;

                //Loop through the number of full chunks and build the byteChunkArray array
                for(i = 0; i < numOfFullChunks; i++){
                    byteChunkArray[i] = startByte+'-'+endByte;

                    //Set new start and stop bytes for next iteration of loop
                    startByte = endByte + 1;
                    endByte += CHUNK_SIZE;
                }

                //Add the last chunk of remaining bytes to the byteChunkArray
                startByte = currentFile.size - remainderBytes;
                endByte = currentFile.size;
                byteChunkArray.push(startByte+'-'+endByte);
            }

            //Start processing the byteChunkArray for the current file, parameter is '' because this is the first chunk being uploaded and there is no attachment Id
            processByteChunkArray('');

        }else{
            //All uploads completed, enable the input and buttons
            j$('input[type=button]').removeAttr("disabled");
            j$('input[type=file]').removeAttr("disabled");
            j$('.fileCount').css('display','none').html('');
            uploadable = [];
            fileId = [];
            upIndex = 0;
        }
    }

    //Uploads a chunk of bytes, if attachmentId is passed in it will attach the bytes to an existing attachment record
    function processByteChunkArray(attachmentId){
        //Proceed if there are still values in the byteChunkArray, if none, all piece of the file have been uploaded
        if(byteChunkArray.length > 0){
            //Determine the byte range that needs to uploaded, if byteChunkArray is like... ['0-179999','180000-359999']
            var indexes = byteChunkArray[0].split('-'); //... get the first index range '0-179999' -> ['0','179999']
            var startByte = parseInt(indexes[0]); //0
            var stopByte = parseInt(indexes[1]); //179999

            var blobChunk = currentFile.slice(startByte , stopByte + 1);
                console.log(blobChunk);

            //Create a new reader object, part of HTML5 File API
            var reader = new FileReader();

            //Read the blobChunk as a binary string, reader.onloadend function below is automatically called after this line
            reader.readAsArrayBuffer(blobChunk);

            //Create a reader.onload function, this will execute immediately after reader.readAsBinaryString() function above;
            reader.onloadend = function(evt){ 
                if(evt.target.readyState == FileReader.DONE){ //Make sure read was successful, DONE == 2
                    //Base 64 encode the data for transmission to the server with JS remoting, window.btoa currently on support by some browsers
                    var base64value = window.btoa(evt.target.result);

                    //Use js remoting to send the base64 encoded chunk for uploading
                    Visualforce.remoting.Manager.invokeAction(
                            '{!$RemoteAction.FileUploadControllerSample.attachBlob}',
                                parentId,attachmentId,currentFile.name,currentFile.type,base64value,                    
                        function(result,event){
                        //Proceed if there were no errors with the remoting call
                        if(event.status == true){
                            //Update the percent of the status bar and percent, first determine percent complete
                            var percentComplete = Math.round((stopByte / currentFile.size) * 100);
                            $upload.find(".percentComplete").text(percentComplete + '%');
                            $upload.find(".percentComplete").css('width',percentComplete + '%');

                            //Remove the index information from the byteChunkArray array for the piece just uploaded.
                            byteChunkArray.shift(); //removes 0 index

                            //Set the attachmentId of the file we are now processing
                            attachmentId = result;

                            //Call process byteChunkArray to upload the next piece of the file
                            processByteChunkArray(attachmentId);

                        }else{
                            //If script is here something broke on the JavasSript remoting call
                            //Add classes to reflect error
                            $upload.attr('data-status','complete');
                            $upload.remove();

                            j$('.fileList').append('<div class="alert alert-success fileCount" role="alert">'+currentFile.name+' failed to upload</div>');
                            //Check and continue the next file to upload
                            upIndex++;
                            checkForUploads();
                        }
                    }); 
                }else{
                    //Error handling for bad read
                    j$('.errorMsg').css('display','block').html("<b>Could not read file</b>");
                }
            };

        }else{
            //This file has completed, all byte chunks have been uploaded, set status on the div to complete
            $upload.attr('data-status','complete');            
            //Call the checkForUploads to find the next upload div that has data-status="incomplete" and start the upload process. 
            j$('.fileList').append('<div class="alert alert-success fileDetails" role="alert">'+currentFile.name+' uploaded successfully</div>');            
            j$('.fileList .alert-success').fadeOut(1000);
            $upload.remove();
            upIndex++;
            checkForUploads();

        }
    }

    </script>    

    <div id="container-{!Account.Id}" class="uploadBox" style="width:400px;margin:0 auto;display:inline-flex">
        <table cellpadding="0" cellspacing="0" class="uploadTable" style="background:none;">
            <tr>
                <td style="width:400px;">
                        <input type="file" multiple="true" id="{!Account.Id}" class="fileClass" name="file[]" file-id="{!Account.Id}" max-length="10" />
                </td>
            </tr>
        </table>
        <input id="uploadButton" type="button" title="Upload" class="btn btn-info" value=" Upload "/>
    </div>
    <div class="upload" data-status="pending" style="display:none;width:400px;"> 
      <div class="percentComplete">0%</div>
      <div class="clear"></div>
       <div class="statusBar">
           <div class="statusBarPercent"></div>
           </div>
           <div id="errorMsg"></div>
</div>
 <center style="width:400px;">
 <div class="alert alert-danger errorMsg" role="alert"></div>
 <div class="alert alert-success fileCount" role="alert"></div>
 <br/>
 <div class="fileList" role="alert"></div>
 </center>

</apex:page>

Apex Class :

global without sharing class FileUploadControllerSample { 
public FileUploadControllerSample(ApexPages.StandardController stdController){ } 
@RemoteAction
    global static String attachBlob(String parentId, String attachmentId, String fileName, String contentType, String base64BlobValue){

        if(attachmentId == '' || attachmentId == null){

            Attachment att = new Attachment(
                ParentId = parentId,
                Body = EncodingUtil.Base64Decode(base64BlobValue),
                Name = fileName,
                ContentType = contentType
            );
            insert att;                      
            return att.Id;           
        }else{
            for(Attachment atm : [select Id, Body from Attachment where Id = :attachmentId]){              
                update new Attachment(Id = attachmentId, Body = EncodingUtil.Base64Decode(EncodingUtil.Base64Encode(atm.Body)));
            }
            return attachmentId;
        }
    } 
}
3
  • download the file and then check if you can view it. If file is not corrupt then check the file size may be its big and sometime depends on internet speed. Aug 19, 2016 at 17:29
  • I have downloaded the file and it is giving the error on view as described. Going further , I have checked the connection. Things are fine. You can copy paaste the code and I am sure you will face the same issue. Aug 19, 2016 at 18:31
  • You are uploading file in chunk. This method work with document but not sure it work with attachment. Aug 19, 2016 at 18:44

1 Answer 1

2

I haven't run it, but from reading the code I suspect the problem is in this line:

update new Attachment(Id = attachmentId, Body = 
        EncodingUtil.Base64Decode(EncodingUtil.Base64Encode(atm.Body)));

In this case the attachBlob remote action has received the next chuck of the file. However, the code above is retrieving the existing Blob body of the attachment in the database and completely ignoring the additional chunk data in base64BlobValue.

Untested, but it should probably be something like:

update new Attachment(Id = attachmentId, Body = 
        EncodingUtil.Base64Decode(
            EncodingUtil.Base64Encode(atm.Body) + base64BlobValue
        )
    );

Watch the Heap size when you are doing this. Things could start breaking with file sizes approaching half the heap limit.

1
  • The Code is not working even after updating the code also , It seems things are going wrong using the Jquery. I am still waiting for a change that works Aug 22, 2016 at 14:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .