Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make drag and drop file upload div, to work like an input type="file"

I am attempting to implement native HTML5 multiple files upload via drag and drop. I have been following tutorials such as http://onehub.com/blog/posts/designing-an-html5-drag-drop-file-uploader-using-sinatra-and-jquery-part-1/ and http://www.html5rocks.com/en/tutorials/file/dndfiles/ but I still haven't found the solution I need.

Basically I want to simulate the functionality of a HTML5 multiple file upload input element, but with a div on witch I listen for the drop events.

In other words, I want to make a form like this one:

<form method="post" action="somesscript.php" enctype="multipart/form-data">
     <input  type="text" />
     <div class="drop">
         <p>Drop files here</p>
     </div>
     <input  type="submit" />
</form>

Work like it was made like this:

<form method="post" action="somesscript.php" enctype="multipart/form-data">
   <input  type="text" />
   <input name="filesToUpload[]" type="file" multiple />
   <input  type="submit" />
</form>

The drag and drop field should be treated as part of the form, and when the form is submitted, I want only than, all the data from the inputs as well as the files array from the drag and drop field to be sent via AJAX to the server.

So far I only have implemented the reading of the files names on a drop event. I want all the files dropped to be added to an array, but I don't know how to access the files themselves, not their attributes, so that latter I can sent this files array on form submit via AJAX together with the rest of the form data.

I want something like :

var data = e.originalEvent.dataTransfer,
               files = data.files,
               filesArray = [],
               filesLength = files.length,
               i;


        for ( i = 0; i < filesLength; i++ ) {
            var file = files[i];
            filesArray.push(file); 
        }

 return filesArray;

Also, I am aware there are plugins for this, but I want to do it native.

like image 679
Maverick Avatar asked May 02 '12 09:05

Maverick


1 Answers

I know you already have the answer years ago :) but here is a 2017 solution, mainly for guys like me looking for a nice looking solution: You can do it with the file input, It will work on modern browsers, for IE you will have to use a fallback.

If you want also the names of the files, and a little fancier UI by using only you can use my example;

This code can be applied on any form and make it do exactly that.

https://jsfiddle.net/artipixel/zkrfcbLd/

var globalFunctions = {};

globalFunctions.ddInput = function(elem) {
  if ($(elem).length == 0 || typeof FileReader === "undefined") return;
  var $fileupload = $('input[type="file"]');
  var noitems = '<li class="no-items"><span class="blue-text underline">Browse</span> or drop here</li>';
  var hasitems = '<div class="browse hasitems">Other files to upload? <span class="blue-text underline">Browse</span> or drop here</div>';
  var file_list = '<ul class="file-list"></ul>';
  var rmv = '<div class="remove"><i class="icon-close icons">x</i></div>'

  $fileupload.each(function() {
    var self = this;
    var $dropfield = $('<div class="drop-field"><div class="drop-area"></div></div>');
    $(self).after($dropfield).appendTo($dropfield.find('.drop-area'));
    var $file_list = $(file_list).appendTo($dropfield);
    $dropfield.append(hasitems);
    $dropfield.append(rmv);
    $(noitems).appendTo($file_list);
    var isDropped = false;
    $(self).on("change", function(evt) {
      if ($(self).val() == "") {
        $file_list.find('li').remove();
        $file_list.append(noitems);
      } else {
        if (!isDropped) {
          $dropfield.removeClass('hover');
          $dropfield.addClass('loaded');
          var files = $(self).prop("files");
          traverseFiles(files);
        }
      }
    });

    $dropfield.on("dragleave", function(evt) {
      $dropfield.removeClass('hover');
      evt.stopPropagation();
    });

    $dropfield.on('click', function(evt) {
      $(self).val('');
      $file_list.find('li').remove();
      $file_list.append(noitems);
      $dropfield.removeClass('hover').removeClass('loaded');
    });

    $dropfield.on("dragenter", function(evt) {
      $dropfield.addClass('hover');
      evt.stopPropagation();
    });

    $dropfield.on("drop", function(evt) {
      isDropped = true;
      $dropfield.removeClass('hover');
      $dropfield.addClass('loaded');
      var files = evt.originalEvent.dataTransfer.files;
      traverseFiles(files);
      isDropped = false;
    });


    function appendFile(file) {
      console.log(file);
      $file_list.append('<li>' + file.name + '</li>');
    }

    function traverseFiles(files) {
      if ($dropfield.hasClass('loaded')) {
        $file_list.find('li').remove();
      }
      if (typeof files !== "undefined") {
        for (var i = 0, l = files.length; i < l; i++) {
          appendFile(files[i]);
        }
      } else {
        alert("No support for the File API in this web browser");
      }
    }

  });
};

$(document).ready(function() {
  globalFunctions.ddInput('input[type="file"]');
});
.blue-text {
  color: blue;
}

.underline {
  text-decoration: underline;
}

.drop-field {
  position: relative;
  text-align: center;
  vertical-align: middle;
}

.drop-field,
.drop-area {
  height: 150px;
  width: 300px;
}

.drop-field .browse {
  z-index: 0;
  position: absolute;
  left: 0;
  bottom: 0;
  right: 0;
  margin: 0 auto;
}

.drop-field .drop-area {
  display: block;
  border: 1px dashed gray;
  position: relative;
}

.drop-field,
.drop-area,
.drop-field .browse {
  transition: all 0.3s;
}

.drop-field.loaded .drop-area {
  border: 1px solid blue;
}

.drop-field .browse {
  opacity: 0;
  transform: translateY(100%);
}

.drop-field.loaded .browse {
  opacity: 1;
  transform: translateY(0);
}

.drop-field.hover .drop-area {
  border: 1px solid black;
}

.drop-field .drop-area input[type="file"] {
  height: 100%;
  width: 100%;
  position: absolute;
  display: block;
  z-index: 3;
  top: 0;
  left: 0;
  opacity: 0.000001;
}

.drop-field .file-list {
  position: absolute;
  z-index: 0;
  top: 0;
  left: 0;
  text-align: center;
}

.drop-field .remove {
  position: absolute;
  left: 20px;
  top: 20px;
  z-index: 4;
  transition: all 0.3s;
  opacity: 0;
  transform: translateY(-100%);
  cursor: pointer;
}

.drop-field .remove:hover {
  color: blue;
}

.drop-field.loaded .remove {
  opacity: 1;
  transform: translateY(0);
}

.drop-field ul li {
  padding: 0;
  text-align: center;
  list-style: none;
}


}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" multiple>
like image 57
Artipixel Avatar answered Nov 16 '22 02:11

Artipixel