18

How to add remove button here like simple remove one by one in files queue like this

enter image description here

The reason why im not using free file upload plugins with OOB plugs because my client requirements is for security purposes and they need simple upload ui without any complicated plugins.

$(function() {
  var dropZoneId = "drop-zone";
  var buttonId = "clickHere";
  var mouseOverClass = "mouse-over";

  var dropZone = $("#" + dropZoneId);
  var ooleft = dropZone.offset().left;
  var ooright = dropZone.outerWidth() + ooleft;
  var ootop = dropZone.offset().top;
  var oobottom = dropZone.outerHeight() + ootop;
  var inputFile = dropZone.find("input");
  document.getElementById(dropZoneId).addEventListener("dragover", function(e) {
    e.preventDefault();
    e.stopPropagation();
    dropZone.addClass(mouseOverClass);
    var x = e.pageX;
    var y = e.pageY;

    if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
      inputFile.offset({
        top: y - 15,
        left: x - 100
      });
    } else {
      inputFile.offset({
        top: -400,
        left: -400
      });
    }

  }, true);

  if (buttonId != "") {
    var clickZone = $("#" + buttonId);

    var oleft = clickZone.offset().left;
    var oright = clickZone.outerWidth() + oleft;
    var otop = clickZone.offset().top;
    var obottom = clickZone.outerHeight() + otop;

    $("#" + buttonId).mousemove(function(e) {
      var x = e.pageX;
      var y = e.pageY;
      if (!(x < oleft || x > oright || y < otop || y > obottom)) {
        inputFile.offset({
          top: y - 15,
          left: x - 160
        });
      } else {
        inputFile.offset({
          top: -400,
          left: -400
        });
      }
    });
  }

  document.getElementById(dropZoneId).addEventListener("drop", function(e) {
    $("#" + dropZoneId).removeClass(mouseOverClass);
  }, true);

  inputFile.on('change', function(e) {
    $('#filename').html("");
    var fileNum = this.files.length,
      initial = 0,
      counter = 0;
    for (initial; initial < fileNum; initial++) {
      counter = counter + 1;
      $('#filename').append('<span class="fa-stack fa-lg"><i class="fa fa-file fa-stack-1x "></i><strong class="fa-stack-1x" style="color:#FFF; font-size:12px; margin-top:2px;">' + counter + '</strong></span> ' + this.files[initial].name + '&nbsp;&nbsp;<span class="fa fa-times-circle fa-lg closeBtn" title="remove"></span><br>');
    }
  });

})
#drop-zone {
  width: 100%;
  min-height: 150px;
  border: 3px dashed rgba(0, 0, 0, .3);
  border-radius: 5px;
  font-family: Arial;
  text-align: center;
  position: relative;
  font-size: 20px;
  color: #7E7E7E;
}
#drop-zone input {
  position: absolute;
  cursor: pointer;
  left: 0px;
  top: 0px;
  opacity: 0;
}
/*Important*/

#drop-zone.mouse-over {
  border: 3px dashed rgba(0, 0, 0, .3);
  color: #7E7E7E;
}
/*If you dont want the button*/

#clickHere {
  display: inline-block;
  cursor: pointer;
  color: white;
  font-size: 17px;
  width: 150px;
  border-radius: 4px;
  background-color: #4679BD;
  padding: 10px;
}
#clickHere:hover {
  background-color: #376199;
}
#filename {
  margin-top: 10px;
  margin-bottom: 10px;
  font-size: 14px;
  line-height: 1.5em;
}
.file-preview {
  background: #ccc;
  border: 5px solid #fff;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.5);
  display: inline-block;
  width: 60px;
  height: 60px;
  text-align: center;
  font-size: 14px;
  margin-top: 5px;
}
.closeBtn:hover {
  color: red;
}
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="drop-zone">
  <p>Drop files here...</p>
  <div id="clickHere">or click here.. <i class="fa fa-upload"></i>
    <input type="file" name="file" id="file" multiple />
  </div>
  <div id='filename'></div>
</div>

Note: I didnt own the code i've been reused it as my resources from other people and modified it for my client

**UPDATE Here my fiddle link

3

5 Answers 5

24
+50

The file list of HTML5 file input is readonly, so when trying to remove a file from it you won't be allowed.

What you need to do is maintain a separate array list (JSON array as per the example).

I have wrapped your X button with a div that hold the file index concatenated to a 'file_' string, and added an onclick function removeLine(obj) that accepts the element as an object.

I have also added a JSON array finalFiles in the global scope as well as moved the inputFile to the global scope.

When the file input changes, I am setting the JSON array with the selected files through :

$.each(this.files,function(idx,elm){
           finalFiles[idx]=elm;
        });

The function removeLine will flush the input file list to allow the same file selection again if the user removed the file by mistake, the function obtains the file index from the wrapper division id, removes the wrapper div then deletes the file from the JSON array.

function removeLine(obj)
    {
      inputFile.val('');
      var jqObj = $(obj);
      var container = jqObj.closest('div');
      var index = container.attr("id").split('_')[1];
      container.remove(); 

      delete finalFiles[index];
      //console.log(finalFiles);
    }

You can the maintain your files when the form submits and send them through AJAX post using FormData in a similar manner to This Article.

var dropZoneId = "drop-zone";
  var buttonId = "clickHere";
  var mouseOverClass = "mouse-over";
var dropZone = $("#" + dropZoneId);
 var inputFile = dropZone.find("input");
 var finalFiles = {};
$(function() {
  

  
  var ooleft = dropZone.offset().left;
  var ooright = dropZone.outerWidth() + ooleft;
  var ootop = dropZone.offset().top;
  var oobottom = dropZone.outerHeight() + ootop;
 
  document.getElementById(dropZoneId).addEventListener("dragover", function(e) {
    e.preventDefault();
    e.stopPropagation();
    dropZone.addClass(mouseOverClass);
    var x = e.pageX;
    var y = e.pageY;

    if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
      inputFile.offset({
        top: y - 15,
        left: x - 100
      });
    } else {
      inputFile.offset({
        top: -400,
        left: -400
      });
    }

  }, true);

  if (buttonId != "") {
    var clickZone = $("#" + buttonId);

    var oleft = clickZone.offset().left;
    var oright = clickZone.outerWidth() + oleft;
    var otop = clickZone.offset().top;
    var obottom = clickZone.outerHeight() + otop;

    $("#" + buttonId).mousemove(function(e) {
      var x = e.pageX;
      var y = e.pageY;
      if (!(x < oleft || x > oright || y < otop || y > obottom)) {
        inputFile.offset({
          top: y - 15,
          left: x - 160
        });
      } else {
        inputFile.offset({
          top: -400,
          left: -400
        });
      }
    });
  }

  document.getElementById(dropZoneId).addEventListener("drop", function(e) {
    $("#" + dropZoneId).removeClass(mouseOverClass);
  }, true);


  inputFile.on('change', function(e) {
    finalFiles = {};
    $('#filename').html("");
    var fileNum = this.files.length,
      initial = 0,
      counter = 0;

    $.each(this.files,function(idx,elm){
       finalFiles[idx]=elm;
    });

    for (initial; initial < fileNum; initial++) {
      counter = counter + 1;
      $('#filename').append('<div id="file_'+ initial +'"><span class="fa-stack fa-lg"><i class="fa fa-file fa-stack-1x "></i><strong class="fa-stack-1x" style="color:#FFF; font-size:12px; margin-top:2px;">' + counter + '</strong></span> ' + this.files[initial].name + '&nbsp;&nbsp;<span class="fa fa-times-circle fa-lg closeBtn" onclick="removeLine(this)" title="remove"></span></div>');
    }
  });



})

function removeLine(obj)
{
  inputFile.val('');
  var jqObj = $(obj);
  var container = jqObj.closest('div');
  var index = container.attr("id").split('_')[1];
  container.remove(); 

  delete finalFiles[index];
  //console.log(finalFiles);
}
#drop-zone {
  width: 100%;
  min-height: 150px;
  border: 3px dashed rgba(0, 0, 0, .3);
  border-radius: 5px;
  font-family: Arial;
  text-align: center;
  position: relative;
  font-size: 20px;
  color: #7E7E7E;
}
#drop-zone input {
  position: absolute;
  cursor: pointer;
  left: 0px;
  top: 0px;
  opacity: 0;
}
/*Important*/

#drop-zone.mouse-over {
  border: 3px dashed rgba(0, 0, 0, .3);
  color: #7E7E7E;
}
/*If you dont want the button*/

#clickHere {
  display: inline-block;
  cursor: pointer;
  color: white;
  font-size: 17px;
  width: 150px;
  border-radius: 4px;
  background-color: #4679BD;
  padding: 10px;
}
#clickHere:hover {
  background-color: #376199;
}
#filename {
  margin-top: 10px;
  margin-bottom: 10px;
  font-size: 14px;
  line-height: 1.5em;
}
.file-preview {
  background: #ccc;
  border: 5px solid #fff;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.5);
  display: inline-block;
  width: 60px;
  height: 60px;
  text-align: center;
  font-size: 14px;
  margin-top: 5px;
}
.closeBtn:hover {
  color: red;
  display:inline-block;
}
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="drop-zone">
  <p>Drop files here...</p>
  <div id="clickHere">or click here.. <i class="fa fa-upload"></i>
    <input type="file" name="file" id="file" multiple />
  </div>
  <div id='filename'></div>
</div>

6
  • Thanks @KAD i will try this. Commented Aug 21, 2015 at 7:08
  • 1
    youre work almost perfect one thing that can perfect this, when you import multiple file then remove one file of the group which is only that file your target, all file in the element also remove, you can see the file element if you delete the part of css #drop-zone input by the way thanks again. Commented Aug 21, 2015 at 7:23
  • How can i submit it? Commented Jun 11, 2016 at 17:23
  • are you using formdata when submitting the files?
    – KAD
    Commented Nov 18, 2016 at 17:29
  • Hello. I have one question. When I remove one file from the list by clicking close icon, form will send those files that remained on the list?
    – X9DESIGN
    Commented May 28, 2017 at 1:46
3

I've done this before for my Dropzone. Feel free to adjust. This is from my Laravel app. You should focus on avatar_refresh_upload. Cut off unnecessary stuff and you're done.

function avatar_refresh_upload() {
    var input = $('input#avatar[type=file]');

    input.replaceWith(input.val('').clone(true));

    $('#selected_file').html('{{ Lang::get('app.profile_avatar_select') }}');
    $('#avatar_refresh_upload').removeAttr('style');
}

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

    $('input:file#avatar').change(function () {
        var file_name = $(this).val();
        if (file_name.length > 10) {
            file_name = file_name.substring(0, 10) + '...';
        }
        $('#selected_file').html('File "' + file_name + '" chosen');
        $('#avatar_refresh_upload').css('display', 'inline-block');
    });

    $('#avatar_refresh_upload').on('click', function () {
        avatar_refresh_upload();
    });

    @if ($user->avatar != '')
    $('#remove_avatar').change(function () {

        if ($(this).is(':checked')) {

            avatar_refresh_upload();
            $('#avatar').prop('disabled', true);
            $('#avatar_preview').css('opacity', '0.5');
            $('#avatar_upload_form_area').css('opacity', '0.5');
            $('#remove_avatar_info').show();

        } else {

            $('#avatar').prop('disabled', false);
            $('#avatar_preview').removeAttr('style');
            $('#avatar_upload_form_area').removeAttr('style');
            $('#remove_avatar_info').removeAttr('style');

        }
    });
    @endif

});

Making long story short - if you want to reset input file after you picked a file for upload but before submitting, you have to run:

input.replaceWith(input.val('').clone(true));
1
  • Ok i will try this Thanks @slick Commented Aug 21, 2015 at 5:09
2

Since we cannot modify the selected files array in the <input type'file' multiple> tag then I have updated you code to show the count of file and to delete all the files if multiple files are selected.

There is a fiddle of the updated code.

$(function () {
    var dropZoneId = "drop-zone";
    var buttonId = "clickHere";
    var mouseOverClass = "mouse-over";

    var dropZone = $("#" + dropZoneId);
    var ooleft = dropZone.offset().left;
    var ooright = dropZone.outerWidth() + ooleft;
    var ootop = dropZone.offset().top;
    var oobottom = dropZone.outerHeight() + ootop;
    var inputFile = dropZone.find("input");
    document.getElementById(dropZoneId).addEventListener("dragover", function (e) {
        e.preventDefault();
        e.stopPropagation();
        dropZone.addClass(mouseOverClass);
        var x = e.pageX;
        var y = e.pageY;

        if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
            inputFile.offset({
                top: y - 15,
                left: x - 100
            });
        } else {
            inputFile.offset({
                top: -400,
                left: -400
            });
        }

    }, true);

    if (buttonId != "") {
        var clickZone = $("#" + buttonId);

        var oleft = clickZone.offset().left;
        var oright = clickZone.outerWidth() + oleft;
        var otop = clickZone.offset().top;
        var obottom = clickZone.outerHeight() + otop;

        $("#" + buttonId).mousemove(function (e) {
            var x = e.pageX;
            var y = e.pageY;
            if (!(x < oleft || x > oright || y < otop || y > obottom)) {
                inputFile.offset({
                    top: y - 15,
                    left: x - 160
                });
            } else {
                inputFile.offset({
                    top: -400,
                    left: -400
                });
            }
        });
    }

    document.getElementById(dropZoneId).addEventListener("drop", function (e) {
        $("#" + dropZoneId).removeClass(mouseOverClass);
    }, true);

    inputFile.on('change', function (e) {
        $('#filename').html("");
        var fileNum = this.files.length,
            initial = 0,
            counter = 0,
            fileNames = "";

        for (initial; initial < fileNum; initial++) {
            counter = counter + 1;
            fileNames += this.files[initial].name + '&nbsp;';
        }
        if(fileNum > 1)
            fileNames = 'Files selected...';
        else
            fileNames = this.files[0].name + '&nbsp;';

        $('#filename').append('<span class="fa-stack fa-lg"><i class="fa fa-file fa-stack-1x "></i><strong class="fa-stack-1x" style="color:#FFF; font-size:12px; margin-top:2px;">'+ fileNum + '</strong></span><span">' + fileNames + '</span>&nbsp;<span class="fa fa-times-circle fa-lg closeBtn" title="remove"></span><br>');

        // add remove event
      $('#filename').find('.closeBtn').click(function(){
          $('#filename').empty();
          inputFile.val('');
      });
      ///End change 
    });

})
7
  • Actually your code is almost working but in UI, the result is when you delete the css part ''#drop-zone input'' you will see the input file in queue flowting around in button, and when you import one or more file then remove them the file in the queue is remain which is in backend it still their. Commented Aug 21, 2015 at 5:34
  • I don't think it is possible to edit the files array of selected files in your <input type='file' multiple> element. It is a security risk so browsers don't allow it.
    – tizzick
    Commented Aug 21, 2015 at 6:51
  • As you can see from this JsFiddle you cannot call splice on the input.files. jsfiddle.net/vpmjqn7u/4 This is was what I was trying to do. The script fails when it reaches the splice. Instead of showing a remove icon after each file name you should just have the use re-select the files if they click the name like this fiddle. jsfiddle.net/0GiS0/Yvgc2
    – tizzick
    Commented Aug 21, 2015 at 6:55
  • I already read that cover question but im also do this thing not for my own purposes but for my client, please suggest other way? Commented Aug 21, 2015 at 7:08
  • I have updated the answer to show a total and delete all selected files when multiple files are selected. If you want to delete individual files from the selected you should try to implement @KAD 's solution.
    – tizzick
    Commented Aug 21, 2015 at 8:19
1
$(function () {

  var dropZoneId = "drop-zone";
  var buttonId = "clickHere";
  var mouseOverClass = "mouse-over";

  var dropZone = $("#" + dropZoneId);
  var ooleft = dropZone.offset().left;
  var ooright = dropZone.outerWidth() + ooleft;
  var ootop = dropZone.offset().top;
  var oobottom = dropZone.outerHeight() + ootop;
  var inputFile = dropZone.find("input");

  var filesArr = [];

  function showFiles() {
    $('#filename').html("");
    var fileNum = filesArr.length;
    for (var i = 0; i < fileNum; i++) {
      $('#filename').append('<div><span class="fa-stack fa-lg"><i class="fa fa-file fa-stack-1x "></i><strong class="fa-stack-1x" style="color:#FFF; font-size:12px; margin-top:2px;">'+ i + '</strong></span> ' + filesArr[i].name + '&nbsp;&nbsp;<span class="fa fa-times-circle fa-lg closeBtn" title="remove"></span></div>');
      }
  }

  function addFiles(e) {
    var tmp;

    // transfer dropped content to temporary array
    if (e.dataTransfer) {
      tmp = e.dataTransfer.files;
    } else if (e.target) {
      tmp = e.target.files;
    }        

    // Copy the file items into the array 
    for(var i = 0; i < tmp.length; i++) {
      filesArr.push(tmp.item(i));
    }

    // remove all contents from the input elemnent (reset it)
    inputFile.wrap('<form>').closest('form').get(0).reset();
    inputFile.unwrap();

    showFiles();
  }    

  document.getElementById(dropZoneId).addEventListener("dragover", function (e) {
    e.preventDefault();
    e.stopPropagation();
    dropZone.addClass(mouseOverClass);
    var x = e.pageX;
    var y = e.pageY;

    if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
        inputFile.offset({
            top: y - 15,
            left: x - 100
        });
    } else {
        inputFile.offset({
            top: -400,
            left: -400
        });
    }
  }, true);

  if (buttonId != "") {
    var clickZone = $("#" + buttonId);

    var oleft = clickZone.offset().left;
    var oright = clickZone.outerWidth() + oleft;
    var otop = clickZone.offset().top;
    var obottom = clickZone.outerHeight() + otop;

    $("#" + buttonId).mousemove(function (e) {
      var x = e.pageX;
      var y = e.pageY;
      if (!(x < oleft || x > oright || y < otop || y > obottom)) {
          inputFile.offset({
              top: y - 15,
              left: x - 160
          });
      } else {
          inputFile.offset({
              top: -400,
              left: -400
          });
      }
    });
  }
  document.getElementById(dropZoneId).addEventListener("drop", function (e) {
    $("#" + dropZoneId).removeClass(mouseOverClass);
    addFiles(e);
  }, true);

  inputFile.on('change', function(e) {
    addFiles(e);
  });

  $('#filename').on('click', '.closeBtn', function(e) {
    e.preventDefault();
    e.stopPropagation();

    var divElem = $(this).parent();
    var index = $('#filename').find('div').index(divElem);
    if ( index !== -1 ) {
      $('#filename')[0].removeChild(divElem[0]);
      filesArr.slice(index,1);
    }
  });

})
4
  • OK thanks i think this is better but will try first thanks @code uniquely Commented Aug 21, 2015 at 5:31
  • can you make an actual example Commented Aug 21, 2015 at 6:23
  • 1
    It is not possible to remove a specific file from this input.files array. It is readonly. The answer to this question covers it stackoverflow.com/questions/11173064/…
    – tizzick
    Commented Aug 21, 2015 at 6:35
  • Updated with the files being written to scoped variable filesArr which can be used to upload the files (Input is reset after files added). HTML Contents rendered from array and removed from array. You can also use the array directly as the data of any AJAX request Commented Aug 21, 2015 at 9:11
0
$(function () {

  var dropZoneId = "drop-zone";
  var buttonId = "clickHere";
  var mouseOverClass = "mouse-over";

  var dropZone = $("#" + dropZoneId);
  var ooleft = dropZone.offset().left;
  var ooright = dropZone.outerWidth() + ooleft;
  var ootop = dropZone.offset().top;
  var oobottom = dropZone.outerHeight() + ootop;
  var inputFile = dropZone.find("input");

  var filesArr = [];

  function showFiles() {
    $('#filename').html("");
    var fileNum = filesArr.length;
    for (var i = 0; i < fileNum; i++) {

                                objectURL = URL.createObjectURL(filesArr[i]);

      $('#filename').append('<div><img title="'+filesArr[i].name+'" id="'+objectURL+'" src="'+objectURL+'" class="pre-visualizacao"><span class="fa-stack fa-lg"><i class="fa fa-file fa-stack-1x "></i><strong class="fa-stack-1x" style="color:#FFF; font-size:12px; margin-top:2px;">'+ i + '</strong></span> ' + filesArr[i].name + '&nbsp;&nbsp;<span class="closeBtn" title="Remover">X</span></div>');

      }
  }

  function addFiles(e) {
    var tmp;

    // transfer dropped content to temporary array
    if (e.dataTransfer) {
      tmp = e.dataTransfer.files;
    } else if (e.target) {
      tmp = e.target.files;
    }        

    // Copy the file items into the array 
    for(var i = 0; i < tmp.length; i++) {
      filesArr.push(tmp.item(i));
      //console.log(i);
    }

    // remove all contents from the input elemnent (reset it)
    inputFile.wrap('<form>').closest('form').get(0).reset();
    inputFile.unwrap();

    showFiles();
  }    

  document.getElementById(dropZoneId).addEventListener("dragover", function (e) {
    e.preventDefault();
    e.stopPropagation();
    dropZone.addClass(mouseOverClass);
    var x = e.pageX;
    var y = e.pageY;

    if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
        inputFile.offset({
            top: y - 15,
            left: x - 100
        });
    } else {
        inputFile.offset({
            top: -400,
            left: -400
        });
    }
  }, true);

  if (buttonId != "") {
    var clickZone = $("#" + buttonId);

    var oleft = clickZone.offset().left;
    var oright = clickZone.outerWidth() + oleft;
    var otop = clickZone.offset().top;
    var obottom = clickZone.outerHeight() + otop;

    $("#" + buttonId).mousemove(function (e) {
      var x = e.pageX;
      var y = e.pageY;
      if (!(x < oleft || x > oright || y < otop || y > obottom)) {
          inputFile.offset({
              top: y - 15,
              left: x - 160
          });
      } else {
          inputFile.offset({
              top: -400,
              left: -400
          });
      }
    });
  }
  document.getElementById(dropZoneId).addEventListener("drop", function (e) {
    $("#" + dropZoneId).removeClass(mouseOverClass);
    addFiles(e);
  }, true);

  /*inputFile.on('change', function(e) {
    addFiles(e);
  });*/

  $('#filename').on('click', '.closeBtn', function(e) {
    e.preventDefault();
    e.stopPropagation();

    var divElem = $(this).parent();
    var index = $('#filename').find('div').index(divElem);
    if ( index !== -1 ) {
      $('#filename')[0].removeChild(divElem[0]);
      filesArr.slice(index,1);
    }
  });
  inputFile.on('change', function(e) {
    $('#filename').html("");
    var fileNum = this.files.length,
      initial = 0,
      counter = 0;
    for (initial; initial < fileNum; initial++) {
      counter = counter + 1;
      objectURL = URL.createObjectURL(this.files[initial]);
      $('#filename').append('<div><img title="'+this.files[initial].name+'" id="'+objectURL+'" src="'+objectURL+'" class="pre-visualizacao"><span class="fa-stack fa-lg"><i class="fa fa-file fa-stack-1x "></i><strong class="fa-stack-1x" style="color:#FFF; font-size:12px; margin-top:2px;">'+ counter + '</strong></span> ' + this.files[initial].name + '&nbsp;&nbsp;<span class="closeBtn" title="Remover">X</span></div>');
    }
  });

});

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.