{"id":4107,"date":"2014-12-19T06:00:48","date_gmt":"2014-12-19T06:00:48","guid":{"rendered":"http:\/\/www.jitendrazaa.com\/blog\/?p=4107"},"modified":"2014-12-19T06:05:09","modified_gmt":"2014-12-19T06:05:09","slug":"salesforce-drag-and-drop-file-uploader-component-with-progress-bar-html5-and-pure-javascript-based","status":"publish","type":"post","link":"https:\/\/www.jitendrazaa.com\/blog\/salesforce\/salesforce-drag-and-drop-file-uploader-component-with-progress-bar-html5-and-pure-javascript-based\/","title":{"rendered":"Salesforce &#8211; Drag and Drop File Uploader Component with Progress Bar &#8211; HTML5 and Pure Javascript Based"},"content":{"rendered":"<figure id=\"attachment_4109\" aria-describedby=\"caption-attachment-4109\" style=\"width: 625px\" class=\"wp-caption alignleft\"><a href=\"https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2014\/12\/HTML5-Drag-And-Drop-File.jpg?ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" class=\"size-large wp-image-4109\" src=\"https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2014\/12\/HTML5-Drag-And-Drop-File.jpg?resize=625%2C125&#038;ssl=1\" alt=\"HTML5 Drag And Drop File\" width=\"625\" height=\"125\" srcset=\"https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2014\/12\/HTML5-Drag-And-Drop-File.jpg?resize=1024%2C205&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2014\/12\/HTML5-Drag-And-Drop-File.jpg?resize=300%2C60&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2014\/12\/HTML5-Drag-And-Drop-File.jpg?resize=624%2C125&amp;ssl=1 624w, https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2014\/12\/HTML5-Drag-And-Drop-File.jpg?w=1108&amp;ssl=1 1108w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><figcaption id=\"caption-attachment-4109\" class=\"wp-caption-text\">HTML5 based Drag And Drop File<\/figcaption><\/figure>\n<p>You may find many ways to upload attachments in Salesforce using\u00a0visualforce\u00a0however most of them uses some Javascript libraries (means either you need to depend on static resources or add CDN in remote site settings) or they do not have progress bar or they are not drag and drop. I thought to create one simple Visualforce component which can show progress bar and have drag and drop capabilities.<\/p>\n<p>Initially i gave though to use visualforce remoting however challenge was how to show progress bar and same challenge was with custom controller or extension also. So, i decided to create one simple Apex REST API to upload attachment.<\/p>\n<p><!--more--><\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n@RestResource(urlMapping='\/DragAndDrop\/v1\/*')\r\nglobal with sharing class DragAndDropRESTAPI\r\n{\r\n    @HttpPost\r\n    global static String attachDoc(){\r\n        RestRequest req = RestContext.request;\r\n        RestResponse res = Restcontext.response;\r\n\r\n        String fName = req.params.get('FileName');\r\n        String parId = req.params.get('parId');\r\n        Blob postContent = req.requestBody; \r\n\r\n        Attachment a = new Attachment (ParentId = parId,\r\n                                       Body = postContent,\r\n                                       Name = fName);\r\n\r\n        insert a;\r\n        return a.Id;\r\n   }\r\n}\r\n<\/pre>\n<p>After this class, I created below Visualforce component which needs only two parameter &#8211; Parent record id where attachment needs to be loaded and height of component.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;apex:component &gt;\r\n         &lt;apex:attribute name=&quot;parentId&quot; type=&quot;String&quot; description=&quot;Parent record where attachment would be attached&quot;\/&gt;\r\n         &lt;apex:attribute name=&quot;DragDropHeight&quot; type=&quot;String&quot; description=&quot;Height in Pixel for Drag and Drop Section&quot;\/&gt;\r\n    &lt;style&gt;\r\n        #holder {\r\n            border: 2px dashed #ccc;\r\n            width: 98%;\r\n            height:95%;\r\n            background-color:#ccc;\r\n            -webkit-border-radius: 8px 8px 8px 8px;\r\n            border-radius: 8px 8px 8px 8px;\r\n            text-align: center;\r\n            }\r\n        #holder span, #uploadCompleted span {\r\n            position: relative;\r\n            top: 30%;\r\n            transform: translateY(-50%);\r\n            text-shadow: 2px 2px 2px #525252;\r\n            font-size:3em;\r\n            color:#A3A3A3;\r\n            }\r\n        #holder.hover { border: 2px dashed #636363; }\r\n\r\n        #uploadStatus span{\r\n            text-shadow: 2px 2px 2px #525252;\r\n            font-size:1em;\r\n             }\r\n\r\n        #holder p { margin: 10px; font-size: 14px; }\r\n        progress { width: 100%;  height:2em;  }\r\n        progress:after { content: '%'; }\r\n        .fail { background: #c00; padding: 2px; color: #fff; }\r\n        .hidden { display: none;}\r\n        .dragDropComponentSize{ height:{!DragDropHeight} ; overflow-y:auto; }\r\n        body{width:98%;font-family: Helvetica,&quot;Helvetica Neue&quot;,Arial,sans-serif;}\r\n    &lt;\/style&gt;\r\n\r\n&lt;article class=&quot;dragDropComponentSize&quot; id=&quot;dndContainer&quot;&gt;\r\n    &lt;div id=&quot;holder&quot; &gt;\r\n        &lt;span id=&quot;holder_txt1&quot;&gt; Drag and Drop file here &lt;\/span&gt;\r\n         &lt;span  id=&quot;holder_txt2&quot; class=&quot;hidden&quot;&gt; Upload &lt;\/span&gt;\r\n    &lt;\/div&gt;\r\n    &lt;p id=&quot;upload&quot; class=&quot;hidden&quot;&gt;&lt;label&gt;Drag &amp;amp; drop not supported by your browser, but you can still upload via this input field:&lt;br \/&gt;&lt;input type=&quot;file&quot; \/&gt;&lt;\/label&gt;&lt;\/p&gt;\r\n    &lt;p id=&quot;filereader&quot;&gt;File API &amp;amp; FileReader API not supported&lt;\/p&gt;\r\n    &lt;p id=&quot;formdata&quot;&gt;XHR2's FormData is not supported&lt;\/p&gt;\r\n    &lt;p id=&quot;progress&quot;&gt;XHR2's upload progress isn't supported&lt;\/p&gt;\r\n    &lt;p id=&quot;uploadStatus&quot; class=&quot;hidden&quot;&gt;&lt;span&gt;Upload progress:&lt;\/span&gt; &lt;progress id=&quot;uploadprogress&quot; min=&quot;0&quot; max=&quot;100&quot; value=&quot;0&quot;&gt;0&lt;\/progress&gt;&lt;\/p&gt;\r\n&lt;\/article&gt;\r\n&lt;script&gt;\r\n    var holder = document.getElementById('holder');\r\n    var holder_txt1 = document.getElementById('holder_txt1');\r\n    var holder_txt2 = document.getElementById('holder_txt2');\r\n    var uploadStatus = document.getElementById('uploadStatus'); \r\n\r\n    var sfdcHostName =window.location.host.split('.')&#x5B;1]; \r\n\r\n    tests = {\r\n      filereader: typeof FileReader != 'undefined',\r\n      dnd: 'draggable' in document.createElement('span'),\r\n      formdata: !!window.FormData,\r\n      progress: &quot;upload&quot; in new XMLHttpRequest\r\n    },\r\n    support = {\r\n      filereader: document.getElementById('filereader'),\r\n      formdata: document.getElementById('formdata'),\r\n      progress: document.getElementById('progress')\r\n    },\r\n    progress = document.getElementById('uploadprogress'),\r\n    fileupload = document.getElementById('upload');\r\n\r\n&quot;filereader formdata progress&quot;.split(' ').forEach(function (api) {\r\n  if (tests&#x5B;api] === false) {\r\n    support&#x5B;api].className = 'fail';\r\n  } else {\r\n    support&#x5B;api].className = 'hidden';\r\n  }\r\n});\r\n\r\nfunction textBeforeDrag(flag){\r\n    if(flag)\r\n    {\r\n        holder_txt1.className = '';\r\n        holder_txt2.className = 'hidden';\r\n    }else{\r\n        holder_txt1.className = 'hidden';\r\n        holder_txt2.className = '';\r\n    }\r\n}\r\n\r\nfunction resetAll()\r\n{\r\n    holder.className = holder_txt1.className = '';\r\n    holder_txt2.className = uploadStatus.className = 'hidden';\r\n}\r\n\r\nfunction readfiles(files) { \r\n\r\n    var formData = tests.formdata ? new FormData() : null;\r\n\r\n      \/\/Not sure why multiple files dropping, so for time being disable multi file functionality\r\n      if(files.length &gt; 1)\r\n      {\r\n          alert('Multi Upload is not supported, please try to upload single file');\r\n          return;\r\n      }\r\n\r\n    for (var i = 0; i &lt; files.length; i++) {\r\n        uploadStatus.className = '';\r\n        holder.className = 'hidden';\r\n        \/\/ now post a new XHR request\r\n        if (tests.formdata) {\r\n          var xhr = new XMLHttpRequest();\r\n\r\n          var sfdcurl = 'https:\/\/'+sfdcHostName+'.salesforce.com\/services\/apexrest\/DragAndDrop\/ v1?FileName='+encodeURIComponent(files&#x5B;i].name)+'&amp;cType= '+encodeURIComponent(files&#x5B;i].type)+ '&amp;parId={!parentId}' ;\r\n\r\n          xhr.open('POST','\/services\/proxy' );\r\n\r\n          \/\/xhr.setRequestHeader(&quot;Content-type&quot;,'multipart\/form-data');\r\n          \/\/xhr.setRequestHeader(&quot;Content-type&quot;,'');\r\n          xhr.setRequestHeader(&quot;Authorization&quot;,&quot;Bearer {!$Api.Session_ID}&quot;);\r\n          xhr.setRequestHeader('SalesforceProxy-Endpoint', sfdcurl);\r\n          xhr.setRequestHeader('X-User-Agent', 'DragAndDropAPI v1.0');\r\n\r\n          xhr.onload = function() {\r\n            progress.value = progress.innerHTML = 100;\r\n            \/\/resetAll();\r\n          };\r\n\r\n          if (tests.progress) {\r\n            xhr.upload.onprogress = function (event) {\r\n              if (event.lengthComputable) {\r\n                var complete = (event.loaded \/ event.total * 100 | 0);\r\n                progress.value = progress.innerHTML = complete;\r\n              }\r\n            }\r\n          }\r\n\r\n          xhr.onreadystatechange=function()\r\n            {\r\n                if (xhr.readyState==4 &amp;&amp; xhr.status != 200)\r\n                {\r\n                    if(xhr.responseText)\r\n                        alert(xhr.responseText);\r\n                    else\r\n                        alert('Some error occurred while uploading file');\r\n\r\n                     console.log(xhr);\r\n                }\r\n            }\r\n\r\n          xhr.send(files&#x5B;i]);\r\n        }\r\n    } \r\n\r\n    \/*\r\n    if(&quot;{!isRefresh}&quot;.toUpperCase()  == &quot;TRUE&quot;)\r\n    {\r\n        location.reload();\r\n    }\r\n    *\/\r\n}\r\n\r\nif (tests.dnd) {\r\n  holder.ondragover = function () {\r\n        this.className = 'hover';\r\n        textBeforeDrag(false);\r\n        return false;\r\n      };\r\n  holder.ondragend = function () {\r\n        this.className = '';\r\n        textBeforeDrag(true);\r\n        return false;\r\n      };\r\n  holder.ondrop = function (e) {\r\n        textBeforeDrag(true);\r\n        this.className = '';\r\n\r\n        e.preventDefault();\r\n        readfiles(e.dataTransfer.files);\r\n  }\r\n} else {\r\n        fileupload.className = 'hidden';\r\n        fileupload.querySelector('input').onchange = function () {\r\n        readfiles(this.files);\r\n  };\r\n}\r\n\r\n&lt;\/script&gt;\r\n&lt;\/apex:component&gt;\r\n<\/pre>\n<p style=\"text-align: justify;\">And we are now good to use above component anywhere in our salesforce application. For example, I used this component in one Visualforce page and added it as inline Visualforce in my Account Page layout.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;apex:page standardController=&quot;Account&quot; docType=&quot;html-5.0&quot; &gt;\r\n    &lt;c:DragDrop parentId=&quot;{!$CurrentPage.parameters.id}&quot; DragDropHeight=&quot;100px&quot; \/&gt;\r\n&lt;\/apex:page&gt;\r\n<\/pre>\n<p>Demo is shown in below youtube video.<\/p>\n<p><iframe loading=\"lazy\" src=\"\/\/www.youtube.com\/embed\/-TLNAqittX8\" width=\"560\" height=\"315\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\n<p><span style=\"text-decoration: underline;\">Note :<\/span> Please make sure you are setting up doctype as html5 in your visualforce page.<br \/>\nThis code is also available on <a title=\"Github Account for Jitendra Zaa\" href=\"https:\/\/github.com\/JitendraZaa\/HTML5_Drag_Drop_Fileuploader\">my github account<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You may find many ways to upload attachments in Salesforce using\u00a0visualforce\u00a0however most of them uses some Javascript libraries (means either you need to depend on static resources or add CDN in remote site settings) or they do not have progress bar or they are not drag and drop. I thought to create one simple Visualforce [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"jz_research_post":"","_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[26,9,18],"tags":[114,126,331,336],"class_list":["post-4107","post","type-post","status-publish","format-standard","hentry","category-web","category-salesforce","category-visualforce","tag-html-5","tag-javascript","tag-salesforce","tag-visualforce"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":4070,"url":"https:\/\/www.jitendrazaa.com\/blog\/salesforce\/access-camera-and-audio-recorder-of-mobile-device-in-visualforce-and-upload-as-chatter-file\/","url_meta":{"origin":4107,"position":0},"title":"Access Camera and Audio recorder of Mobile device in Visualforce and upload as chatter file","author":"Jitendra","date":"November 29, 2014","format":false,"excerpt":"In this article we will see how to use Camera and Audio recorder of mobile device in Visualforce and upload as chatter file. It may look that it is very tricky to access device camera and audio control in Visualforce however you may be right if there were no HTML5.\u2026","rel":"","context":"In &quot;HTML&quot;","block_context":{"text":"HTML","link":"https:\/\/www.jitendrazaa.com\/blog\/category\/webtech\/web\/"},"img":{"alt_text":"Visualforce Camera Access - Front Page","src":"https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2014\/11\/Visualforce-Camera-Access-Front-Page-168x300.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":6021,"url":"https:\/\/www.jitendrazaa.com\/blog\/salesforce\/behold-yourself-summer-17-is-here-to-break-legacy-visualforce-navigation-code\/","url_meta":{"origin":4107,"position":1},"title":"Behold Yourself &#8211; Summer 17 is here to break legacy Visualforce Navigation code in Lightning Experience","author":"Jitendra","date":"May 8, 2017","format":false,"excerpt":"In Summer 17, URLFOR method in Visualforce would not work in Lightning Experience if used directly. Even sforce.one API is not fully compatible.","rel":"","context":"In &quot;Salesforce&quot;","block_context":{"text":"Salesforce","link":"https:\/\/www.jitendrazaa.com\/blog\/category\/salesforce\/"},"img":{"alt_text":"Salesforce Summer 17 Logo","src":"https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2017\/05\/Salesforce-Summer-17-Logo.gif?fit=460%2C325&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2649,"url":"https:\/\/www.jitendrazaa.com\/blog\/salesforce\/get-dom-elementid-of-the-visualforce-components\/","url_meta":{"origin":4107,"position":2},"title":"Get DOM ElementID of the Visualforce components","author":"Jitendra","date":"January 19, 2012","format":false,"excerpt":"How to get the DOM ElementID of the Visualforce components in Salesforce","rel":"","context":"In &quot;Salesforce&quot;","block_context":{"text":"Salesforce","link":"https:\/\/www.jitendrazaa.com\/blog\/category\/salesforce\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":4102,"url":"https:\/\/www.jitendrazaa.com\/blog\/salesforce\/salesforce-faq-part-20-lightning-questions\/","url_meta":{"origin":4107,"position":3},"title":"Salesforce interview question related to Lightning framework &#8211; Part 20","author":"Jitendra","date":"February 4, 2015","format":false,"excerpt":"Salesforce interview questions for Salesforce developers and admin , mostly related to newly released Salesforce Lightning components and applications","rel":"","context":"In &quot;Salesforce&quot;","block_context":{"text":"Salesforce","link":"https:\/\/www.jitendrazaa.com\/blog\/category\/salesforce\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":4667,"url":"https:\/\/www.jitendrazaa.com\/blog\/salesforce\/barcode-decoder-in-salesforce1-very-fast-and-simple\/","url_meta":{"origin":4107,"position":4},"title":"Javascript based Barcode decoder in Salesforce1 &#8211; Very fast and Simple","author":"Jitendra","date":"July 10, 2015","format":false,"excerpt":"Very fast and Simple Barcode decoder in Salesforce1 using quaggaJS javascript library","rel":"","context":"In &quot;Salesforce&quot;","block_context":{"text":"Salesforce","link":"https:\/\/www.jitendrazaa.com\/blog\/category\/salesforce\/"},"img":{"alt_text":"Barcode decoder sample in Salesforce 1","src":"https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2015\/07\/download-1.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2015\/07\/download-1.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2015\/07\/download-1.png?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":5737,"url":"https:\/\/www.jitendrazaa.com\/blog\/salesforce\/use-lightning-component-in-visualforce-page\/","url_meta":{"origin":4107,"position":5},"title":"Use Lightning Component in Visualforce Page","author":"Jitendra","date":"September 22, 2016","format":false,"excerpt":"How to use Lightning Out to surface Lightning Component on Visualforce Pages","rel":"","context":"In &quot;Salesforce&quot;","block_context":{"text":"Salesforce","link":"https:\/\/www.jitendrazaa.com\/blog\/category\/salesforce\/"},"img":{"alt_text":"Use Lightning Components in Visualforce Pages","src":"https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2016\/09\/Use-Lightning-Components-in-Visualforce-Pages.jpg?fit=862%2C501&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2016\/09\/Use-Lightning-Components-in-Visualforce-Pages.jpg?fit=862%2C501&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2016\/09\/Use-Lightning-Components-in-Visualforce-Pages.jpg?fit=862%2C501&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.jitendrazaa.com\/blog\/wp-content\/uploads\/2016\/09\/Use-Lightning-Components-in-Visualforce-Pages.jpg?fit=862%2C501&ssl=1&resize=700%2C400 2x"},"classes":[]}],"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.jitendrazaa.com\/blog\/wp-json\/wp\/v2\/posts\/4107","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.jitendrazaa.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.jitendrazaa.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.jitendrazaa.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.jitendrazaa.com\/blog\/wp-json\/wp\/v2\/comments?post=4107"}],"version-history":[{"count":6,"href":"https:\/\/www.jitendrazaa.com\/blog\/wp-json\/wp\/v2\/posts\/4107\/revisions"}],"predecessor-version":[{"id":4114,"href":"https:\/\/www.jitendrazaa.com\/blog\/wp-json\/wp\/v2\/posts\/4107\/revisions\/4114"}],"wp:attachment":[{"href":"https:\/\/www.jitendrazaa.com\/blog\/wp-json\/wp\/v2\/media?parent=4107"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.jitendrazaa.com\/blog\/wp-json\/wp\/v2\/categories?post=4107"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.jitendrazaa.com\/blog\/wp-json\/wp\/v2\/tags?post=4107"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}