0

I'm trying to display each image inside the custom style input file label before user uploads in the database. The script I'm using works at displaying only one image at the time and it is always located somewhere random. I'd like each image to appear as if they are inside the label. Each image does not display right inside the label. What am I doing wrong?

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

        reader.readAsDataURL(input.files[0]);
              }
            }
            $(".img1").change(function() {
              readURL(this);
            });
            $(".img2").change(function() {
              readURL(this);
            });
            $(".img3").change(function() {
              readURL(this);
            });
            $(".img4").change(function() {
              readURL(this);
            });
.col-md-4 {
  width: 33.33333333%;
  display: inline-block;
  margin-bottom: 15%;
}

.labelav.largeFile:after {
  position: relative;
  width: 5% !important;
  max-width: 100%;
  content: "Upload Photo + ";
  text-align: center;
  padding: 10%;
  border-radius: 10px;
  border: 5px dashed #ccc;
  color: #ccc;
  font-family: "Helvetica Neue", Helvetica, Arial;
  font-size: medium;
}

.labelav.largeFile:hover:after {
  background: #ccc;
  color: #fff;
  cursor: pointer;
}

.labelav.largeFile input.file {
  visibility: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
  <div class='col-md-4'>
    <label class="labelav largeFile" for="file">
      <input type="file" id="file" class="file img1" name="photo1" />
      <img id="photo1" src="#" alt="" />
    </label>
  </div>

  <div class='col-md-4'>
    <label class="labelav largeFile" for="file">
      <input type="file" id="file" class="file img2" name="photo2" />
      <img id="photo2" src="#" alt="" />
    </label>
  </div>

  <div class='col-md-4'>
    <label class="labelav largeFile" for="file">
      <input type="file" id="file" class="file img3" name="photo3" />
      <img id="photo3" src="#" alt="" />
    </label>
  </div>

  <div class='col-md-4'>
    <label class="labelav largeFile" for="file">
      <input type="file" id="file" class="file img4" name="photo4" />
      <img id="photo4" src="#" alt="" />
    </label>
  </div>
</form>
Sebastian Farham
  • 797
  • 2
  • 8
  • 24

2 Answers2

1

The reason the image winds up in the last spot is because in your readURL function, you overwrite the .onload property so that only the last value (which points to #photo4) is stored:

        function readURL(input) {
          if (input.files && input.files[0]) {
            var reader = new FileReader();

            // All you are doing here is setting the value of the 
            // onload property...
            reader.onload = function(e) {
              $('#photo1').attr('src', e.target.result);
            }

            // And here, you are overwriting the last value and storing
            // a new one...
            reader.onload = function(e) {
              $('#photo2').attr('src', e.target.result);
            }

            // And here, you are overwriting the last value and storing
            // a new one...
            reader.onload = function(e) {
              $('#photo3').attr('src', e.target.result);
            }

            // This is the function that will actually run
            // when the load event of the reader fires because it is 
            // the last value you are storing in the propery:
            reader.onload = function(e) {
              $('#photo4').attr('src', e.target.result);
            }
            reader.readAsDataURL(input.files[0]);
          }
        }

Additionally, each of your input type=file elements uses the same id, which is not ever a good idea. All ids should be unique.

Now, since you have so much duplication in your code, we can reduce it to this working version:

// No need to set up essentially the same event handler separately
// This will set each of the input type=file elements up to the same
// change event handling function. The 'e' argument represents the
// change event itself:
$(".file").on("change", function(e) {
  if (this.files && this.files[0]) {
    var reader = new FileReader();
      
    // Use W3C DOM Event Standard for setting up event listeners
    // instead of `onclick`, `onload`, etc. properties. We can use
    // the same one function no matter which input type=file was clicked
    // Here 'evt' represents the load event of the reader
    reader.addEventListener("load", function(evt) {
      // Set the src attribute of the next element sibling
      // to the input that was changed:
      e.target.nextElementSibling.setAttribute('src', evt.target.result);
    });
    
    reader.readAsDataURL(this.files[0]);
  }
});
.col-md-4 {
  width: 33.33333333%;
  display: inline-block;
  margin-bottom: 15%;
}

.labelav.largeFile:after {
  position: relative;
  width: 5% !important;
  max-width: 100%;
  content: "Upload Photo + ";
  text-align: center;
  padding: 10%;
  border-radius: 10px;
  border: 5px dashed #ccc;
  color: #ccc;
  font-family: "Helvetica Neue", Helvetica, Arial;
  font-size: medium;
}

.labelav.largeFile:hover:after {
  background: #ccc;
  color: #fff;
  cursor: pointer;
}

.labelav.largeFile input.file {
  visibility: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
  <div class='col-md-4'>
    <label class="labelav largeFile" for="file1">
      <input type="file" id="file1" class="file img1" name="photo1">
      <img id="photo1" src="#" alt="">
    </label>
  </div>

  <div class='col-md-4'>
    <label class="labelav largeFile" for="file2">
      <input type="file" id="file2" class="file img2" name="photo2">
      <img id="photo2" src="#" alt="">
    </label>
  </div>

  <div class='col-md-4'>
    <label class="labelav largeFile" for="file3">
      <input type="file" id="file3" class="file img3" name="photo3">
      <img id="photo3" src="#" alt="">
    </label>
  </div>

  <div class='col-md-4'>
    <label class="labelav largeFile" for="file4">
      <input type="file" id="file4" class="file img4" name="photo4">
      <img id="photo4" src="#" alt="">
    </label>
  </div>
</form>
Scott Marcus
  • 57,085
  • 6
  • 34
  • 54
  • `:-O` you lost me... My code was noobish for a reason dude lol. I can read your code sure but it is way over my head as of right now lol – Sebastian Farham May 03 '17 at 21:19
  • I understand the first part. – Sebastian Farham May 03 '17 at 21:20
  • @SebastianFarham The only thing that is different in your `onload` functions and your `change` functions is the references to the `image` element that should be updated and the `input type=file` that was clicked. My code just eliminates all that redundancy and utilizing `this` (which will referent the `` that was clicked) and `e.target` (which does the same thing but for the `load` event) can figure out which element to work with. – Scott Marcus May 03 '17 at 21:46
  • @SebastianFarham See my latest updated answer for a working version that contains comments to explain each part. – Scott Marcus May 03 '17 at 21:48
  • When i tried it inside of my environment it didnt fire but it does now I dont know what happened. Thanks for that. But the display problem still remain I cant seem to display each image inside the labels. – Sebastian Farham May 03 '17 at 21:51
  • @SebastianFarham Images won't display inside of a `label` - - they will either display in an `img` element or as the background of another element. My code does place the image into the correct `img` placeholder. – Scott Marcus May 03 '17 at 21:54
  • Ok so I will place the img with position:absolute. Thanks. – Sebastian Farham May 03 '17 at 21:55
  • I have solved the display issue and it works without position:absolute... since it is part of my question and is NOT a duplicate, I'd like to edit your answer so that the future users get the FULL concept of my problem that is now solved. – Sebastian Farham May 03 '17 at 23:06
  • @SebastianFarham That's not how Stack Overflow works. Just add your comment (as you've done) to the answer and we're good. – Scott Marcus May 03 '17 at 23:42
  • But it's not a duplicate... The full question was to display each picture inside the labels... I posted the full answer. – Sebastian Farham May 03 '17 at 23:51
0

With Scott Marcus answer, here's the FULL answer to my question which is NOT a duplicate. On top of javascript issues I also had display issues. Note that you may have to play with the pixels to work with your own code. For some reason I had to write something different from the code in my program for the snippet to work...

So here it is:

  
  // No need to set up essentially the same event handler separately
// This will set each of the input type=file elements up to the same
// change event handling function. The 'e' argument represents the
// change event itself:
$(".file").on("change", function(e) {
  if (this.files && this.files[0]) {
    var reader = new FileReader();
      
    // Use W3C DOM Event Standard for setting up event listeners
    // instead of `onclick`, `onload`, etc. properties. We can use
    // the same one function no matter which input type=file was clicked
    // Here 'evt' represents the load event of the reader
    reader.addEventListener("load", function(evt) {
      // Set the src attribute of the next element sibling
      // to the input that was changed:
      e.target.nextElementSibling.setAttribute('src', evt.target.result);
    });
    
    reader.readAsDataURL(this.files[0]);
  }
});
.col-md-4 .labelav.largeFile{
    width:33.33%;
  display: inline-block;
  margin-bottom: 10%;
    border-radius: 10px;
  border: 5px dashed #ccc;
 min-height:200px;
      cursor:pointer;
    background: url("http://www.startuppassion.eu/wp-content/uploads/2017/03/plus-sign.png") no-repeat center;
        background-size: 40%;
}
.labelav img{
    width:30%;
    position:absolute;
    left:20px;
}
.labelav.largeFile img:after {
  width:100% !important;
  display:inline-block;
    max-width:100%;
}
.labelav.largeFile input.file {
width:0px;
height:0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
  <div class='col-md-4 imgblock'>
    <label class="labelav largeFile" for="file1">
      <input type="file" id="file1" class="file img1" name="photo1">
      <img id="photo1" src="#" alt="">
    </label>
  </div>

  <div class='col-md-4 imgblock'>
    <label class="labelav largeFile" for="file2">
      <input type="file" id="file2" class="file img2" name="photo2">
      <img id="photo2" src="#" alt="">
    </label>
  </div>

  <div class='col-md-4 imgblock'>
    <label class="labelav largeFile" for="file3">
      <input type="file" id="file3" class="file img3" name="photo3">
      <img id="photo3" src="#" alt="">
    </label>
  </div>

  <div class='col-md-4'>
    <label class="labelav largeFile" for="file4">
      <input type="file" id="file4" class="file img4" name="photo4">
      <img id="photo4" src="#" alt="">
    </label>
  </div>
</form>
Sebastian Farham
  • 797
  • 2
  • 8
  • 24
  • This is not the correct way to wrap this up. Now my answer and this answer overlap. The correct thing to do is mark my answer as "the" answer and just add a comment to it explaining what changes you made. My code answers the question you asked which was how to get the image to display in the correct element, not how to put an element in the correct spot . The `position:absolute` is not what your question was asking. – Scott Marcus May 03 '17 at 23:56
  • Well, I thought I was being clear in the question but turns out there was a misunderstanding. The problem was CSS and JS related. I will mark you as answer and remove mine, if you update your answer with the new CSS so that the next users get FULL answer. – Sebastian Farham May 04 '17 at 01:17
  • As I've said a number of times, your comment at the bottom of my answer is the best way to keep it all clear. – Scott Marcus May 04 '17 at 01:21
  • It's the best way. Future visitors will find everything in one answer and the comments. This is how we do it at SO. – Scott Marcus May 04 '17 at 01:59