-
-
Save jsmithdev/ac71db810ffa48b9c9de98f174d6498f to your computer and use it in GitHub Desktop.
JavaScript snippet for uploading fille to Salesforce as ContentVersion and sharing to record as ContentDocumentLink via jsforce and jquery.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<apex:page> | |
<head> | |
<script src="{!$Resource.jquery224}"></script> <!-- https://jquery.com/ --> | |
<script src="{!$Resource.jsforce170}"></script> <!-- https://jsforce.github.io/ --> | |
<script>$j = jQuery.noConflict();</script> | |
</head> | |
<body> | |
<form> | |
<input type="file" id="fileInput"/> | |
</form> | |
</body> | |
<script> | |
var conn = new jsforce.Connection({ accessToken: '{!$Api.Session_Id}' }); | |
/** | |
* Uses Chatter REST API to upload files up to 2GB. | |
*/ | |
function uploadFile() { | |
// ... show waiting indicator | |
var fileInput = $j('#fileInput'); | |
if ( $j.trim( fileInput.val() ).length == 0 ) { | |
// ... hide waiting indicator | |
return; | |
} | |
// https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL | |
var file = fileInput[0].files[0]; | |
var fileName = getFileNameWithExtension( file ); | |
var reader = new FileReader(); | |
reader.addEventListener('load', function() { | |
saveFile( fileName, reader.result, '{!record.id}' ); | |
}); | |
reader.readAsDataURL( file ); | |
} | |
/** | |
* Saves the file asynchronously to Salesforce and shares it to the record. | |
* | |
* @param fileName | |
* Name of the file, for best results should include extension (e.g. 'file.txt') | |
* @param base64 | |
* Base64 encoded file data | |
* @param recordId | |
* The Salesforce record to share the file to | |
* | |
* Returns a promise per the jsforce library. | |
*/ | |
function saveFile( fileName, base64, recordId ) { | |
var path = '/services/data/v40.0'; | |
return conn.requestPost( path + '/composite/', { | |
'allOrNone' : true, | |
'compositeRequest' : [ | |
{ | |
'method' : 'POST', | |
'url' : path + '/sobjects/ContentVersion', | |
'referenceId' : 'newFile', | |
'body' : { | |
'Title' : fileName, | |
'PathOnClient' : fileName, | |
'VersionData' : base64, | |
'FirstPublishLocationId' : recordId | |
} | |
} | |
] | |
}) | |
.then( validateCompositeResponse ) | |
.then( function( response ) { | |
// get new file id | |
var contentVersionId = null; | |
for ( var i = 0; i < response.compositeResponse.length; i++ ) { | |
if ( response.compositeResponse[i].referenceId === 'newFile' ) { | |
contentVersionId = response.compositeResponse[i].body.id; | |
break; | |
} | |
} | |
// ... do something with the new file id | |
}).catch( function( err ) { | |
console.error( err ); | |
// ... show error to user | |
}).then( function() { | |
// this last 'then' after the 'catch' acts like a finally block of try..catch..finally | |
// https://stackoverflow.com/questions/35999072/what-is-the-equivalent-of-bluebird-promise-finally-in-native-es6-promises | |
// ... hide waiting indicator | |
}); | |
} | |
/** | |
* Gets the name with extension of a file input reference, like 'file.txt'. | |
* Replaces any other periods (.) with underscores (_) otherwise Salesforce | |
* ignores all text in the filename after the first dot. | |
* | |
* @param file | |
* js reference of a file retrieved from an html input element | |
* e.g. fileInput.files[0] | |
*/ | |
function getFileNameWithExtension( file ) { | |
var extIndex = file.name.lastIndexOf( '.' ); | |
var extension = file.name.substring( extIndex ); | |
var fileName = file.name.substring( 0, extIndex ); | |
fileName = fileName.replace( /\./g, '_' ); | |
fileName += extension; | |
return fileName; | |
} | |
/** | |
* Checks each sub-response for an error code | |
* and throws error if finds one, else does nothing. | |
*/ | |
function validateCompositeResponse( response ) { | |
return new Promise( function( resolve, reject ) { | |
console.log('validating composite response'); | |
for ( var i = 0; i < response.compositeResponse.length; i++ ) { | |
var body = response.compositeResponse[i].body[0]; | |
// ignore the 'processing halted' messages as that just indicates | |
// that sub-request wasn't the one that blew up, keep looking | |
if ( body && body.errorCode && body.errorCode != 'PROCESSING_HALTED' ) { | |
reject( body.message ); | |
} | |
} | |
resolve( response ); | |
}); | |
} | |
</script> | |
</apex:page> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment