Can not preview multiple uploading files in form - javascript

In a multipart form, I can preview a single uploading image using:
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
let image = new Image();
image.src = `${e.target.result}`;
image.className = "img-thumbnail"
let closeBtn = `<button type="button" class="close"></button>`;
let wrapper = $('<div class="image-wrapper" />');
$('#images-to-upload').append(wrapper);
$(wrapper).append(image);
$(wrapper).append(closeBtn);
}
reader.readAsDataURL(input.files[0]);
}
}
$("#imgInput").change(function () {
readURL(this);
});
But I'd like to preview ALL uploading images, so I made this adjustment to the code above by adding a for loop:
function readURL(input) {
if (input.files && input.files[0]) {
let files = input.files;
for (var i = 0; i < input.files.length; i++) {
var reader = new FileReader();
reader.onload = function (e) {
let image = new Image();
image.src = `${e.target.result[i]}`;
image.className = "img-thumbnail"
let closeBtn = `<button type="button" class="close"></button>`;
let wrapper = $('<div class="image-wrapper" />');
$('#images-to-upload').append(wrapper);
$(wrapper).append(image);
$(wrapper).append(closeBtn);
}
};
reader.readAsDataURL(input.files[i]); // error here
}
}
But now I get this error:
143 Uncaught TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'
How can I fix this?

It's because the reader.readAsDataURL(input.files[i]); is outside the loop. But this is not how you do this. The FileReader can process only one file at the time. This means you have to create an instance of the FileReader for each image in the input.
I would suggest to split it into 2 functions for readability.
function previewImage(file) {
const reader = new FileReader();
reader.onload = function (e) {
let image = new Image();
image.src = e.target.result;
image.className = "img-thumbnail";
let closeBtn = `<button type="button" class="close"></button>`;
let wrapper = $('<div class="image-wrapper" />');
$("#images-to-upload").append(wrapper);
$(wrapper).append(image);
$(wrapper).append(closeBtn);
};
reader.readAsDataURL(file);
}
function readURL(input) {
if (input.files.length) {
Array.from(input.files).forEach((file) => previewImage(file));
}
}
I made some changes:
if (input.files.length) { - the file input always have files FileList object so no need to check if it exists, and you just check if it has a length, meaning at least one file is present
Array.from(input.files) - transforms FileList into a regular array fo you can use array functions, like forEach
The rest is pretty much the same. In image.src = e.target.result;, there's no need to make it string as it is already a string. Also the result set on the FileReader class cannot be array.

Related

HTMLImageElement onclick

I am trying to add an onclick event that calls a function selectMain(name). When I run my project it doesn't seem to generate the onclick attribute from the image.
function previewFiles() {
var preview = document.querySelector('#preview');
var files = document.querySelector('input[type=file]').files;
function readAndPreview(file) {
if (/\.(jpe?g|png)$/i.test(file.name)) {
var reader = new FileReader();
reader.addEventListener("load", function() {
var image = new Image();
image.height = 100;
image.title = file.name;
image.src = this.result;
image.onclick = selectMain(file.name);
preview.appendChild(image);
}, false);
reader.readAsDataURL(file);
}
}
if (files) {
[].forEach.call(files, readAndPreview);
}
}
function selectMain(name) {
var files = document.querySelector('input[type=file]').files;
Array.from(files).forEach(file => {
if (file.name == name) {
document.getElementById("primaryPhoto").value = file;
}
});
}
Try thisimage.onclick = function(){ selectMain(file.name); };
In addition to what Gagik answered (the early selectMain call is definitiely an issue even if it doesn't fix the whole thing), what is
document.getElementById("primaryPhoto").value = file;
supposed to do? If primaryPhoto is a input[type=file] element, then that won't work due to security limitations
You cannot set the value of a file picker from a script
Source.
(/\.(jpeg?g|png)$/i.test(file.name))
In the existing code, function get invoked on the time of render on dom.
here is the correct way to bind event.
var image = new Image();
image.height = 100;
image.title = file.name;
image.src = this.result;
image.onclick =()=>{selectMain(file.name)};

How do i check if the src attribute of an image is valid?

I'm trying to create a meme generator, and when the user clicks a button, a meme should be generated, but if the image has not been selected, an empty image is created, so I want to create a sort of check to find out if the image has been set first.
Here's the code to select the image
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('.blah')
.attr('src', e.target.result);
};
reader.readAsDataURL(input.files[0]);
}
}
after this i'm trying to create a check if the src attribute is set, but the code still runs and creates an empty image
function createMeme(){
let make = $('.blah');
let out = $('#img-out > img');
if (make.src) {
return "oijoijojioij";
} else {
html2canvas([document.getElementById('gen-img')], {
onrendered: function (canvas) {
var imagedata = canvas.toDataURL('image/png');
var imgdata = imagedata.replace(/^data:image\/(png|jpg);base64,/, "");
//ajax call to save image inside folder
$.ajax({
url: 'save-image.php',
data: {
imgdata:imgdata
},
type: 'post',
success: function (response) {
console.log(response);
out.attr('src', response);
}
})
}
});
}
}
You can use Javascript Image class instead of FileReader()
var img=new Image();
img.onload=function(){
...
};
img.onerror=function(){
...
};
img.src=URL;

Javascript FileReader with multiple files , how iterate files name?

I'm trying to write a multi upload image logic. This is the code i use:
function readURL(input,index) {
for (var z = 0; z < input.files.length; z++) {
var FileZ=input.files[z];
if (input.files && input.files[z]) {
var reader = new FileReader();
reader.onload = function (e) {
var i = new Image();
i.src=e.target.result;
i.onload = function(){
//ajax crop to 500x350
var arrExt = FileZ.name.split('.');
if(i.width>=500 && i.height>=350) {
$.ajax({
url: 'ajax/cropImage.php',
type: 'POST',
data: 'base64='+e.target.result+"&ext="+arrExt[(arrExt.length-1)],
success: function(data) {
//here i insert the image in html.
}
});
} else {
alert("Image too big");
}
};
}
reader.readAsDataURL(input.files[z]);
}
}
}
This code works correctly, i can upload and see after ajaxCrop.php the resulting images. The problem comes when i try to upload image with different extensions. If i try to upload one jpg and one png, only one of this photo will be cropped. The problem is in
var arrExt = FileZ.name.split('.');
Here the file name is always the same, at z=0 name='image.jpg' and at z=1 name='image.jpg' (the name should be 'image.png'). So i get an error when i try to crop a 'false' jpg... How i can get the correct 'name at index'?

Display a spinner as img src attribute is set using FileReader()

I'm using the following code to read a image file and set the result as the src for an image attribute,
document.getElementsByClassName("upload-image"),
function(fileElement) {
var previewElement = document.createElement("img");
previewElement.style.display = "block";
fileElement.parentNode.insertBefore(previewElement, fileElement);
var fileReader = new FileReader();
fileReader.onload = function(event) {
previewElement.src = event.target.result;
};
fileElement.addEventListener("change", updateImagePreview, false);
updateImagePreview();
function updateImagePreview() {
var file = fileElement.files[0];
if (file) {
fileReader.readAsDataURL(file);
} else {
var placeholderSrc = fileElement.getAttribute("data-placeholder");
if (placeholderSrc) {
previewElement.src = placeholderSrc;
} else {
previewElement.removeAttribute("src");
}
}
}
}
This works well, however I know that it takes some time for the actual image src to be set and for the image to be displayed.
Is there anyway for me to detect when the image src is set, and loaded, and ready to be displayed?

how to loop this function?

Thanks to some help on here I have a way of previewing images selected for and upload using:
<input type='file' name="files[]" onchange="readURL(this);" multiple />
<div id="previews"></div>
<script>
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
var container = $('#previews');
var image = $('<img>').attr('src', e.target.result).width(150);
image.appendTo(container);
};
reader.readAsDataURL(input.files[0]);
}
}
</script>
I was wondering how to loop this function for each file selected on the input? I just don't see where to use something like .each()
edit:
am trying this.. but its wrong somewhere, as it displays 2 previews but both of the same image?
function readURL(input) {
$.each(input.files,function(i) {
var reader = new FileReader();
reader.onload = function (e) {
var container = $('#previews');
var image = $('<img>').attr('src', e.target.result).width(150);
image.appendTo(container);
};
reader.readAsDataURL(input.files[0]);
});
}
input.files is a FileList, which acts like an array.
You can use jQuery.each on it like any other array.
You just need to loop over the last line, where the file is selected.
function readURL(input) {
var reader = new FileReader();
reader.onload = function (e) {
var container = $('#previews');
var image = $('<img>').attr('src', e.target.result).width(150);
image.appendTo(container);
};
$.each(input.files,function(i) {
reader.readAsDataURL(input.files[i]);
});
}

Categories

Resources