0

I have 3 input[type="file"] allow user upload 3 images, and user only can select 3 images on each input, but what I trying to implement is:

Consider user click on first input, now user can select 1 image, but if user select 2 or 3 image I want to send second or third image to next inputs. For example if user click on first input, and select 3 images, first image should set on first input, second should set on second input and also third to third input. Also if click second or third input, it should send each image to each input file.

function imgToData(input) {
  if (input.files && input.files[0]) {

    var File = new FileReader();
    File.onload = function() {
      var Img = new Image();

      Img.onload = function() {
        $('#' + input.id + '-val').val(Img.src);
        $('#' + input.id + '-preview').attr('src', Img.src).css('visibility', 'visible').fadeIn();
      };
      Img.src = File.result;
    };

    File.readAsDataURL(input.files[0]);
  }
}

$("input[type='file']").each(function() {
  $(this).change(function() {
    if (parseInt($(this).get(0).files.length) > 3) {
      alert("You can only upload a maximum of 3 images");
    } else {
      imgToData(this);
    }
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <input type="file" id="img-1" multiple/>
  <input type="text" id="img-1-val" />
  <img id="img-1-preview" width="30" />
</div>

<div>
  <input type="file" id="img-2" multiple/>
  <input type="text" id="img-2-val" />
  <img id="img-2-preview" width="30" />
</div>

<div>
  <input type="file" id="img-3" multiple/>
  <input type="text" id="img-3-val" />
  <img id="img-3-preview" width="30" />
</div>

This is what I tried so far:

$.each($(this)[0].files, function(i,v){
if(i==0){
// go to input 1
} else if(i==1){
// go to input 2
} else if(i==2){
// go to input 3
}

});

But no idea how should send value to each related input. Any idea?

Padideh
  • 139
  • 2
  • 13
  • You cannot programmatically set the values of file inputs, so what you're asking is not possible. You will need to remove the `multiple` attributes on the inputs and force the user to select each file individually. – Rory McCrossan Feb 01 '18 at 10:40
  • @RoryMcCrossan But I saw many website did this, Also used `multiple`, So it is possible. – Padideh Feb 01 '18 at 11:15
  • Do you have an example of one of those sites? – Rory McCrossan Feb 01 '18 at 11:15
  • That is using a single `multiple` file input and then appending new `li` elements for each file it contained. It is not using different `input type="file"` controls and updating them, because as I mentioned in my first comment, that's not possible. – Rory McCrossan Feb 01 '18 at 11:17
  • @RoryMcCrossan You right. So assume I remove second and third input, then how can create element for each selected image? any example? – Padideh Feb 01 '18 at 11:22
  • 1
    Sure, you can loop over the `files` collection to create elements and append them to the DOM, like [this](https://stackoverflow.com/questions/268490/jquery-document-createelement-equivalent). You can also restrict the selection to 3 files by placing `$(this)[0].files <= 3` in an `if` condition. – Rory McCrossan Feb 01 '18 at 11:25
  • @RoryMcCrossan actually it's possible to set the values of file inputs. not cross platform compatible but it is possible. – Endless Feb 01 '18 at 19:29
  • @Endless do you have a source for that? Be interested to see how it works – Rory McCrossan Feb 01 '18 at 19:36
  • https://stackoverflow.com/questions/16943605/remove-a-filelist-item-from-a-multiple-inputfile/47642446#47642446 – Endless Feb 01 '18 at 19:52

1 Answers1

2

With some change in your logic you can achieve this. First you need to remove all input except first one then add multiple attribute, then create your preview and value dynamically like what @Rory said in comment but you need a loop to create element for each image but 3 times.

function imgToData(input) {
  if ($('img').length < 3) {
    if (input.files) {

      var length = input.files.length;
      if (length <= 3) {
        $.each(input.files, function(i, v) {
            var n = i + 1;
            var File = new FileReader();
            File.onload = function(event) {
              $('<img/>').attr({
                src: event.target.result,
                class: 'img',
                id: 'img-' + n + '-preview',
              }).appendTo('body');

              $('<input/>').attr({
                type: 'text',
                value: event.target.result,
                id: 'img-' + n + '-val'
              }).appendTo('body');
            };

            File.readAsDataURL(input.files[i]);
          });
        }
        else {
          alert('Only 3 images allowed!');
        }
      }
    } else {
      alert('Only 3 images allowed!');
    }
  }


  $('input[type="file"]').change(function(event) {
    imgToData(this);
  });
.img {
  height: 100px;
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" id="upload" multiple/>

Extra note: For better UI experience you can create 3 element like li then replace each image with that li and hide input[type="file"] and trigger it by something like this:

$('#UploaderDiv').click(function(){
  $('#upload').click();
});
Pedram
  • 15,766
  • 10
  • 44
  • 73