Web Design File Upload Drag and Drop

I work on an RSS reader app called Readerrr (editor'southward note: link removed as site seems dead). I wanted to enrich the feed import experience by making allowing for drag and drop file upload alongside the traditional file input. Sometimes drag and drop is a more comfortable style to select a file, isn't it?

View Demo

Markup

This markup doesn't take anything specifically to practise with drag and drop. It'due south only a normal, functional<grade>, albeit with some extra HTML elements for potential states.

          <form form="box" method="post" action="" enctype="multipart/course-data">   <div class="box__input">     <input form="box__file" blazon="file" name="files[]" id="file" data-multiple-caption="{count} files selected" multiple />     <label for="file"><strong>Cull a file</strong><span class="box__dragndrop"> or drag information technology here</span>.</label>     <button course="box__button" type="submit">Upload</button>   </div>   <div form="box__uploading">Uploading…</div>   <div class="box__success">Done!</div>   <div form="box__error">Error! <span></span>.</div> </form>        

Nosotros'll hide those states until we demand them:

          .box__dragndrop, .box__uploading, .box__success, .box__error {   display: none; }        

A little caption:

  • Regarding states: .box__uploading element will be visible during the Ajax process of file upload (and the others will still exist subconscious). Then .box__success or .box__error will be shown depending on what happens.
  • input[type="file"] and label are the functional parts of the form. I wrote near styling these together in my mail nigh customizing file inputs. In that mail service I also described the purpose of [data-multiple-explanation] attribute. The input and characterization as well serve as an culling for selecting files in the standard style (or the only manner if drag and drop isn't supported).
  • .box__dragndrop will be shown if a browser supports elevate and drop file upload functionality.

Feature detection

We tin't 100% rely on browsers supporting drag and drop. Nosotros should provide a fallback solution. And so: feature detection. Drag & driblet file upload relies on a number of different JavaScript API's, and then we'll demand to check on all of them.

Outset, drag & drop events themselves. Modernizr is a library yous tin can trust all about feature detection. This examination is from there:

          var div = certificate.createElement('div'); render ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)        

Next we demand to bank check the FormData interface, which is for forming a programmatic object of the selected file(s) so they can exist sent to the server via Ajax:

          return 'FormData' in window;        

Last, we need the DataTransfer object. This 1 is a bit tricky because there is no bullet-proof style to detect the availability of the object before user's first interaction with the drag & drop interface. Not all browsers betrayal the object.

Ideally we'd like to avert UX like…

  • "Drag and drop files here!"
  • [User drags and drops files]
  • "Oops just kidding drag and drib isn't supported."

The trick here is to check the availability of FileReader API right when the document loads. The idea behind this is that browsers that support FileReader back up DataTransfer too:

          'FileReader' in window        

Combining the code above into self-invoking anonymous role…

          var isAdvancedUpload = function() {   var div = certificate.createElement('div');   return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && 'FormData' in window && 'FileReader' in window; }();        

… will enable us to make an constructive feature support detection:

          if (isAdvancedUpload) {   // ... }        

With this working feature detection, now we tin allow the users know they tin elevate & drop their files into our course (or not). Nosotros tin can style the form by adding a class to it in the example of support:

          var $class = $('.box');  if (isAdvancedUpload) {   $class.addClass('has-advanced-upload'); }        
          .box.has-avant-garde-upload {   groundwork-color: white;   outline: 2px dashed black;   outline-offset: -10px; } .box.has-advanced-upload .box__dragndrop {   display: inline; }        

No issues at all if drag & drop file upload is not supported. Wsers will be able to upload files via skillful ol' input[type="file"]!

Note on browser support: Microsoft Edge has a bug which stops drag and drop from working. It sounds like they are enlightened of it and hope to set up information technology. (Update: link to bug removed as the link stopped working. Now that Edge is Chromium, presumably, it's non a problem anymore.)

Drag 'n' Drib

Here we go, here'southward the good stuff.

This part deals with adding and removing classes to the grade on the different states like when the user is dragging a file over the form. Then, catching those files when they are dropped.

          if (isAdvancedUpload) {    var droppedFiles = false;    $form.on('drag dragstart dragend dragover dragenter dragleave drop', function(e) {     due east.preventDefault();     e.stopPropagation();   })   .on('dragover dragenter', function() {     $grade.addClass('is-dragover');   })   .on('dragleave dragend drib', function() {     $form.removeClass('is-dragover');   })   .on('drop', function(e) {     droppedFiles = east.originalEvent.dataTransfer.files;   });  }        
  • e.preventDefault() and e.stopPropagation() prevent any unwanted behaviors for the assigned events beyond browsers.
  • e.originalEvent.dataTransfer.files returns the list of files that were dropped. Soon you lot will run across how to use the data for sending these files to the server.

Adding and removing .is-dragover when necessary enables us to visually betoken when it is safe for a user to drop the files:

          .box.is-dragover {   groundwork-color: grey; }        

Selecting Files In a Traditional Way

Sometimes dragging & dropping files is not very comfy way for selecting files for upload. Especially when a user is in front end of a small-scale screen size reckoner. Therefore information technology would be nice to let users choose the method they adopt. The file input and label are here to allow this. Styling them both in the way I've described allows usa to keep the UI consistant:

Ajax Upload

In that location is no cross-browser way to upload dragged & dropped files without Ajax. Some browsers (IE and Firefox) do not allow setting the value of a file input, which then could be submitted to server in a usual way.

This won't work:

          $class.find('input[type="file"]').prop('files', droppedFiles);        

Instead, we'll use Ajax when the form is submitted:

          $class.on('submit', part(e) {   if ($grade.hasClass('is-uploading')) return false;    $form.addClass('is-uploading').removeClass('is-error');    if (isAdvancedUpload) {     // ajax for mod browsers   } else {     // ajax for legacy browsers   } });        

The .is-uploading class does double duty: information technology prevents the form from beingness submitted repeatedly (return faux) and helps to indicate to a user that the submission is in progress:

          .box.is-uploading .box__input {   visibility: none; } .box.is-uploading .box__uploading {   display: cake; }        

Ajax for modern browsers

If this was a form without a file upload, we wouldn't need to take two dissimilar Ajax techniques. Unfortunately, file uploading via XMLHttpRequest on IE ix and below is not supported.

To distinguish which Ajax method will work, we can use our existing isAdvancedUpload examination, because the browsers which back up the stuff I wrote before, also support file uploading via XMLHttpRequest. Hither's lawmaking that works on IE 10+:

          if (isAdvancedUpload) {   east.preventDefault();    var ajaxData = new FormData($form.get(0));    if (droppedFiles) {     $.each( droppedFiles, function(i, file) {       ajaxData.append( $input.attr('name'), file );     });   }    $.ajax({     url: $form.attr('action'),     type: $form.attr('method'),     data: ajaxData,     dataType: 'json',     cache: simulated,     contentType: imitation,     processData: faux,     complete: function() {       $grade.removeClass('is-uploading');     },     success: function(information) {       $form.addClass( data.success == true ? 'is-success' : 'is-error' );       if (!data.success) $errorMsg.text(data.fault);     },     error: function() {       // Log the fault, evidence an alert, whatever works for you     }   }); }        
  • FormData($form.get(0)) collects information from all the form inputs
  • The $.each() loop runs through the dragged & dropped files. ajaxData.append() adds them to the information stack which will be submitted via Ajax
  • data.success and data.error are a JSON format answer which will be returned from the server. Hither's what that would be like in PHP:
          <?php   // ...   die(json_encode([ 'success'=> $is_success, 'error'=> $error_msg])); ?>        

Ajax for legacy browsers

This is substantially for IE 9-. We do not need to collect the dragged & dropped files because in this instance (isAdvancedUpload = simulated), the browser does not support drag & driblet file upload and the class relies only on the input[blazon="file"].

Strangely plenty, targeting the form on a dynamically inserted iframe does the trick:

          if (isAdvancedUpload) {   // ... } else {   var iframeName  = 'uploadiframe' + new Date().getTime();     $iframe   = $('<iframe name="' + iframeName + '" style="display: none;"></iframe>');    $('body').suspend($iframe);   $form.attr('target', iframeName);    $iframe.one('load', function() {     var information = JSON.parse($iframe.contents().find('body' ).text());     $form       .removeClass('is-uploading')       .addClass(data.success == true ? 'is-success' : 'is-error')       .removeAttr('target');     if (!data.success) $errorMsg.text(information.fault);     $grade.removeAttr('target');     $iframe.remove();   }); }        

Automated Submission

If you lot have a elementary course with only a elevate & driblet area or file input, it may be a user convenience to avoid requiring them to printing the button. Instead, yous can automatically submit the course on file drop/select by triggering the submit event:

          // ...  .on('drib', function(e) { // when drag & drop is supported   droppedFiles = due east.originalEvent.dataTransfer.files;   $form.trigger('submit'); });  // ...  $input.on('modify', function(e) { // when drag & drib is Not supported   $grade.trigger('submit'); });        

If drag & drop area is visually well-designed (it'southward obvious to the user what to practice), you lot might consider hiding the submit button (less UI can exist good). But be careful when hiding a control similar that. The button should be visible and functional if for some reason JavaScript is not available (progressive enhancement!). Adding a .no-js class proper name to and removing it with JavaScript will do the trick:

          <html grade="no-js">   <head>     <!-- remove this if you employ Modernizr -->     <script>(function(east,t,due north){var r=e.querySelectorAll("html")[0];r.className=r.className.supplant(/(^|\s)no-js(\south|$)/,"$1js$2")})(document,window,0);</script>   </caput> </html>        
          .box__button {   display: none; } .no-js .box__button {   display: block; }        

Displaying the Selected Files

If you're non going to exercise auto-submission there should exist an indication to the user if they have selected files successfully:

          var $input    = $form.find('input[type="file"]'),     $label    = $class.find('label'),     showFiles = function(files) {       $label.text(files.length > 1 ? ($input.attr('data-multiple-explanation') || '').replace( '{count}', files.length ) : files[ 0 ].name);     };  // ...  .on('drop', part(e) {   droppedFiles = e.originalEvent.dataTransfer.files; // the files that were dropped   showFiles( droppedFiles ); });  //...  $input.on('change', role(eastward) {   showFiles(due east.target.files); });        

When JavaScript Is Non Bachelor

Progressive enhancement is about the idea that a user should be able to consummate the master tasks on a website no affair what. File uploading is no exception. If for some reason JavaScript is not available, the interface volition look like this:

The page volition refresh on form submission. Our JavaScript for indicating the result of submission is useless. That means nosotros take to rely on server-side solution. Hither's how it looks and works in the demo page:

          <?php    $upload_success = nothing;   $upload_error = '';    if (!empty($_FILES['files'])) {     /*       the lawmaking for file upload;       $upload_success – becomes "true" or "false" if upload was unsuccessful;       $upload_error – an error message of if upload was unsuccessful;     */   }  ?>        

And some adjustments for the markup:

          <course grade="box" method="post" action="" enctype="multipart/form-data">    <?php if ($upload_success === null): ?>    <div form="box__input">     <!-- ... -->   </div>    <?php endif; ?>    <!-- ... -->    <div course="box__success"<?php if( $upload_success === true ): ?> style="brandish: block;"<?php endif; ?>>Washed!</div>   <div class="box__error"<?php if( $upload_success === fake ): ?> style="display: block;"<?php endif; ?>>Error! <bridge><?=$upload_error?></bridge>.</div>  </form>        

That'south it! This already-long article could take been even longer, merely I think this volition get y'all going with a responsible drag and drop file upload characteristic on your ain projects.

Check out the demo for more (view source to see the no-jQuery-dependency JavaScript):

View Demo

hublerloored.blogspot.com

Source: https://css-tricks.com/drag-and-drop-file-uploading/

0 Response to "Web Design File Upload Drag and Drop"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel