1

I want to preview multiple images as they would appear on the post when submitted. This code below works fine for one file. It displays exactly as I would hope it would.

$('input[name="filesToUpload[]"]').on('change', function(event) {
        $('body').css('overflow','hidden');
        $('body').css('margin-right','1.7rem');
        $('.navbar_more').css('margin-right','1.7rem');
        $('.post_preview').removeClass('cssdisplaynone');
        var checkfiles = $(this)[0].files;
        if(checkfiles) {
            var filesAmount = checkfiles.length;
            for(var i = 0; i < filesAmount; i++) {
                var previewHTML = '';
                var file = $(this)[0].files[i];
                var fileType = file.type;
                if(fileType.search('image') >= 0) {
                    var img = new Image();
                    var imgsrc = window.URL.createObjectURL(file);
                    img.src = imgsrc;
                    img.onload = function(event) {
                        previewHTML += '<div class="post_file ' + ((i == 1) ? 'post_file_show' : '') + '" style="padding-bottom: ' + ((this.height / this.width) * 100) + '%">';
                        previewHTML += '<img src="' + imgsrc + '" width="' + this.width + '" height="' + this.height + '" />';
                        if(filesAmount > 1) {
                            previewHTML += '<span class="post_count">' + i + '/' + filesAmount + '</span>';
                        }
                        previewHTML += '</div>';
                        $('.post_preview').find('.post_content').append(previewHTML);
                    }
                }
            }
        }
    });

Single File Output:

<div class="post_file post_file_show" style="padding-bottom: 75%"><img src="BLOB URL 1" width="480" height="360"></div>

However, when I try to preview two or more images, for instance, the output isn't what I expect it to be.

Two File Output:

<div class="post_file " style="padding-bottom: 100%"><img src="BLOB URL 2" width="1024" height="1024"><span class="post_count">2/2</span></div>
<div class="post_file " style="padding-bottom: 100%"><img src="BLOB URL 2" width="1024" height="1024"><span class="post_count">2/2</span></div>
<div class="post_file " style="padding-bottom: 75%"><img src="BLOB URL 2" width="480" height="360"><span class="post_count">2/2</span></div>

Three File Output:

<div class="post_file " style="padding-bottom: 100%"><img src="BLOB URL 3" width="1024" height="1024"><span class="post_count">3/3</span></div>
<div class="post_file " style="padding-bottom: 100%"><img src="BLOB URL 3" width="1024" height="1024"><span class="post_count">3/3</span></div>
<div class="post_file " style="padding-bottom: 153.45454545454544%"><img src="BLOB URL 3" width="550" height="844"><span class="post_count">3/3</span></div>
<div class="post_file " style="padding-bottom: 100%"><img src="BLOB URL 3" width="1024" height="1024"><span class="post_count">3/3</span></div>
<div class="post_file " style="padding-bottom: 153.45454545454544%"><img src="BLOB URL 3" width="550" height="844"><span class="post_count">3/3</span></div>
<div class="post_file " style="padding-bottom: 75%"><img src="BLOB URL 3" width="480" height="360"><span class="post_count">3/3</span></div>

This isn't my strong field. I am perfectly content with PHP, but for a good user experience, I need to use javascript to preview images before upload so users could describe the post, rather than have them add it afterwards, which is jarring.

EDIT

Here is updated code that actually resolves almost all the issues. The issues of repeating is gone. The issue of incorrect URL is gone. I got this from How to pass parameters into image load event?.

However, this does pose the problem that this is done async, so the files append out of order... I'm trying to find solution to that right now that isn't "evil" as many posts keep saying...

if($(this)[0].files[i].type.search('image') >= 0) {
                var img = new Image();
                img.dataurl = objectUrl;
                img.j = i;
                img.onload = function(event) {
                    previewHTML += '<div class="post_file ' + ((this.j == 0) ? 'post_file_show' : '') + '"  style="padding-bottom: ' + ((this.height / this.width) * 100) + '%">';
                    previewHTML += '<img src="' + this.dataurl + '" width="' + this.width + '" height="' + this.height + '" />';
                    if(fileList.length > 1) {
                        previewHTML += '<span class="post_count">' + (this.j + 1) + '/' + fileList.length + '</span>';
                    }
                    previewHTML += '</div>';
                    $('.post_preview').find('.post_content').append(previewHTML);
                    previewHTML = '';
                }
                img.src = objectUrl;
            }
theadomist
  • 53
  • 4

1 Answers1

0

Although I am not an expert, but I kind of stick to your issue as it seemed so simple yet was not doable, so after trying a dozen things, I came to know, image's source shall be set after onload event defined, moreover your onload function was only firing once so put a new keyword, now 2 or more images are shown herez the code, I am sure you can use it, and improve it if needed

$('input[name="filesToUpload[]"]').on('change', function(event) {
        $('body').css('overflow','hidden');
        $('body').css('margin-right','1.7rem');
        $('.navbar_more').css('margin-right','1.7rem');
        $('.post_preview').removeClass('cssdisplaynone');
        var checkfiles = $(this)[0].files;
        if(checkfiles) {
            var filesAmount = checkfiles.length;

            for(var i = 0; i < filesAmount; i++) {
                var previewHTML = '';
                var file = $(this)[0].files[i];
                var fileType = file.type;
                if(fileType.search('image') >= 0) {

                    var img = new Image();
                    var imgsrc = window.URL.createObjectURL(file);

                    img.onload = new function(event) {

                        previewHTML += '<div class="post_file ' + ((i == 1) ? 'post_file_show' : '') + '" style="padding-bottom: ' + ((this.height / this.width) * 100) + '%">';
                        previewHTML += '<img src="' + imgsrc + '" width="' + this.width + '" height="' + this.height + '" />';
                        if(filesAmount > 1) {
                            previewHTML += '<span class="post_count">' + i + '/' + filesAmount + '</span>';
                        }

                        previewHTML += '</div>';
                        $('.post_preview').find('.post_content').append(previewHTML);
                    }

                    img.src = imgsrc;


                }
            }
        }


    });
Usman Waheed
  • 70
  • 1
  • 8
  • With the change of ((i == 0) ? 'post_file_show' : '') and ' + (i + 1) + ' this would otherwise appear to work, but the problem is that the height and width is not working. They show as undefined. – theadomist Sep 15 '19 at 21:58
  • it must be something with the sequence of events / flow as when I put a new button and on its click used simple javascript to get image height/width its working fine (so I first browse the files, they are displayed then click on Try button: `` I used the code to assign id before the line where image src is being set:`img.setAttribute("id", "img"+i);` – Usman Waheed Sep 17 '19 at 06:28
  • 1
    Setting previewHTML = ''; after appending solved the issue of duplicates. And I found another post that actually answered the issue of incorrect URL... but now I realize that this runs async, so the files display out of order, which isn't how they will display uploaded. – theadomist Sep 18 '19 at 02:31