3

I'm working on uploading multiple images one at a time by dynamically generating the input field and image element. However, my code doesn't display the images on the dynamically generated image element.

<button type="button" class="btn btn-sm btn-info add-image"><i class="ti-image"></i>  Add image</button>
<br><br>
<div class="images"></div>
$(document).ready(function() {
  var max_image = 10;
  var count = 1;

  $('.add-image').click(function(e) {
    e.preventDefault();
    if (count < max_image) {
      count++;
      $('.images').append(`<div class="input" style="width:100px;height:120px;border:2px dashed lightgrey;float:left;margin:8px">    
        <input type ="file" class ="fileup 1" id ="file'+count+'" style="width:100%; height:100%; opacity:0; position: absolute">    
        <img id ="image'+count+'" src="" style="width:100%; height:100%;">    
        <span class="btn btn-sm btn-danger delete" style="position:relative;bottom:20px"><I class="ti-trash"></i></span>    
      </div>`);

      $(document).on('change', '#file' + count, function() {
        readURL(this);
      });

      function readURL(input) {
        if (input.files && input.files[0]) {
          var reader = new FileReader();
          reader.onload = function(e) {
            $('#image' + count).attr('src', e.target.result);
          }
          reader.readAsDataURL(input.files[0]);
        }
      }
    } else {
      alert("Only a maximum of 10 images is allowed");
    }
  });

  $('.images').on("click", ".delete", function(e) {
    e.preventDefault();
    $(this).parent('div').remove();
    y--;
  })
});
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
Browyn Louis
  • 218
  • 3
  • 14
  • not sure what your code is about, but file doesn't return image, maybe this could help: https://stackoverflow.com/questions/7650587/using-javascript-to-display-a-blob – Flash Thunder Jan 10 '21 at 13:51

2 Answers2

1

Instead of making event handler for all files use can just one event handler and then inside your readURL function use .closest('div').find('img') to add src to image tag.

Demo Code :

$(document).ready(function() {
  // allowed maximum input fields
  var max_image = 10;

  // initialize the counter for textbox
  var count = 1;

  // handle click event on Add More button
  $('.add-image').click(function(e) {

    e.preventDefault();

    if (count < max_image) {

      count++; // increment the counter

      // validate the condition

      $('.images').append(`<div class="input" style="width:100px;height:120px;border:2px dashed lightgrey;float:left;margin:8px">

<input type ="file" class ="fileup 1" id ="file'+count+'" style="width:100%; height:100%; opacity:0; position: absolute">

<img id ="image'+count+'" src="" style="width:100%; height:100%;">

<span class="btn btn-sm btn-danger delete" style="position:relative;bottom:20px"><I class="ti-trash"></i></span>

</div>`); // add input field
 } else {
      alert("Only a maximum of 10 images is allowed");
    }
 });

  // handle click event of the remove link
  $('.images').on("click", ".delete", function(e) {
    e.preventDefault();
    $(this).parent('div').remove(); // remove input field
    y--; // decrement the counter
  })
  
  //put this outside..
  $(document).on('change', '.images input[type=file]', function() {
    readURL(this);
  });

  function readURL(input) {
    if (input.files && input.files[0]) {
      var reader = new FileReader();
      reader.onload = function(e) {
      //get closest div and then find img add img there
        $(input).closest('div').find('img').attr('src', e.target.result);
      }
      reader.readAsDataURL(input.files[0]);
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" class="btn btn-sm btn-info add-image"><i class="ti-image"></i>  Add image</button>
<br><br>
<div class="images"></div>
Swati
  • 28,069
  • 4
  • 21
  • 41
1

There's several issues to address here.

  • Don't nest your event handlers
  • Put CSS rules in an external stylesheet, not inline in the HTML
  • You're not appending the count value to the template literal using the correct syntax
  • Aside from the above, do not use incremental id attributes. Group elements with common behaviour by class and attach a single event handler to them all. This is what you should do with the delegated event handler you're using.

The latter point is what fixes your issue, as it will allow you to target the img which was clicked on and update its specific src attribute to the content of the file which was selected.

$(document).ready(function() {
  var max_image = 10;

  $(document).on('change', '.fileup', function() {
    readURL(this, $(this).next('img'));
  });

  function readURL(input, $target) {
    if (input.files && input.files[0]) {
      var reader = new FileReader();
      reader.onload = function(e) {
        $target.attr('src', e.target.result);
      }
      reader.readAsDataURL(input.files[0]);
    }
  }

  $('.add-image').click(function(e) {
    e.preventDefault();

    if ($('div.input').length < max_image) {
      $('.images').append(`<div class="input">
        <input type="file" class="fileup" />
        <img />
        <span class="btn btn-sm btn-danger delete">
          <i class="ti-trash">X</i>
        </span>
      </div>`);
    } else {
      alert("Only a maximum of 10 images is allowed");
    }
  });

  $('.images').on("click", ".delete", function(e) {
    e.preventDefault();
    $(this).closest('div').remove();
  })
});
div.input {
  width: 100px;
  height: 120px;
  border: 2px dashed lightgrey;
  float: left;
  margin: 8px;
}

input.fileup {
  width: 100%;
  height: 100%;
  opacity: 0;
  position: absolute;
}

div.input img {
  width: 100%;
  height: 100%;
}

span.delete {
  position: relative;
  bottom: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" class="btn btn-sm btn-info add-image">
  <i class="ti-image"></i>  
  Add image
</button>
<br><br>
<div class="images"></div>
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339