Onyx
Onyx

Reputation: 5780

Why is my function only applying SRC property only to the first uploaded image?

The function successfully creates N image elements with a class of new-avatar-picture, however, it only adds SRC property to the first image. I'm not getting any errors in the console either.

function displayInputImage(input) {

    var files = input.files;

    for (var i = 0; i < files.length; i++) {
        var file = files[i];
        var reader = new FileReader();
        var x = document.createElement("img");

        reader.onload = function(e) {
            x.setAttribute("src", e.target.result);
        }

        reader.readAsDataURL(file);

        x.className = "new-avatar-picture";
        $('.upload-btn-wrapper').append(x);
    }

}

Upvotes: 1

Views: 25

Answers (2)

Rory McCrossan
Rory McCrossan

Reputation: 337627

The issue with your logic is due to the fact that onload() of the reader fires after the loop completes, so x will refer to the last element in the set. Hence that single element gets its src set N times.

To fix this you could use a closure:

function displayInputImage(input) {
  for (var i = 0; i < input.files.length; i++) {
    var $img = $("<img />");
    (function($imgElement) {
      var reader = new FileReader();
      reader.onload = function(e) {
        $imgElement.prop("src", e.target.result);
      }
      reader.readAsDataURL(input.files[i]);

      $imgElement.addClass("new-avatar-picture");
      $('.upload-btn-wrapper').append($imgElement);
    }($img));
  }
}

Alternatively you could create the new img elements only after the content of the file is read:

function displayInputImage(input) {
  for (var i = 0; i < input.files.length; i++) {
    var reader = new FileReader();
    reader.onload = function(e) {
      $('<img />').addClass('new-avatar-picture').prop('src', e.target.result).appendTo('.upload-btn-wrapper');
    }
    reader.readAsDataURL(input.files[i]);
  }
}

Upvotes: 1

Ahmad
Ahmad

Reputation: 12737

One way to do that is to give each image a new property, I call it temp_src so that the browser will not try to load the images right away.

Then in the .onload event, loop through all images that you have created and give each of them the proper src value, by copying it from its temp_src property.

Something like:

var reader = new FileReader();
function displayInputImage(input) {

  var files = input.files;

  for (var i = 0; i < files.length; i++) {
    var file = files[i];

    var x = document.createElement("img");

    x.setAttribute("class", "temp_img");
    x.setAttribute("temp_src", file);

    reader.readAsDataURL(file);

    x.className = "new-avatar-picture";
    $('.upload-btn-wrapper').append(x);
  }

}

reader.onload = function(e) {
  var images = document.getElementsByClassName("tmp_img");
  images.forEach(function(img) {
    img.setAttribute("src", img.temp_src);
  });

}

Upvotes: 0

Related Questions