I have the following code:
oFReader = new FileReader(), rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;
oFReader.onload = function (oFREvent) {
$("#preview").append("<img src='" + oFREvent.target.result + "' />");
};
function loadImageFile() {
if (document.getElementById("uploadImage").files.length === 0) { return; }
$.each(document.getElementById("uploadImage").files, function (index, value) {
if (!rFilter.test(value.type)) { alert("You must select a valid image file!"); return; }
oFReader.readAsDataURL(value);
});
}
It is intended to take a collection of images that have been dragged onto a input of type file, and then preview those images in a div. My issue is that when I run this, only the last image appears. If I add a break point into my javascript and step through the code, both images are displayed.
I am assuming that this is happening because oFReader.onload is being called twice very quickly. I had considered using setTimeout or possibly declaring oFReader inside of my loop to try to avoid the conflict, but I'm wondering if there is a more elegant solution?
You need a separate FileReader object for each file you are reading.
.readDataAsURL() is an asynchronous method. It finishes some time later after you call it. In your .each() loop, you are trying to read a new file before the previous one is done, thus stopping it before it completes.
You could do something like this:
function loadImageFile() {
if (document.getElementById("uploadImage").files.length === 0) { return; }
$.each(document.getElementById("uploadImage").files, function (index, value) {
var oFReader = new FileReader(), rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;
if (!rFilter.test(value.type)) { alert("You must select a valid image file!"); return; }
oFReader.onload = function (oFREvent) {
$("#preview").append("<img src='" + oFREvent.target.result + "' />");
};
oFReader.readAsDataURL(value);
});
}
Related
I think my javascript in my php file is in conflict with my javascript file.
I have a script that checks of the image is smaller then 2MB and a script that shows the image you selected in a small version. But the second part does not work when the first script is active. how do I fix this?
script in HTML
<script>
window.onload = function() {
var uploadField = document.getElementById("frontImages");
uploadField.onchange = function() {
if(this.files[0].size > 2000000){
alert("File is too big!");
this.value = "";
};
};
var uploadField = document.getElementById("itemImages");
uploadField.onchange = function() {
if(this.files[0].size > 200){
alert("File is too big!");
this.value = "";
};
};
}
</script>
.js file
$("#frontImages").change(function () {
if ($('#frontImages').get(0).files.length > 0) {
$('#frontImages').css('background-color', '#5cb85c');
} else {
$('#frontImages').css('background-color', '#d9534f');
}
});
$("#itemImages").change(function () {
if ($('#itemImages').get(0).files.length > 0) {
$('#itemImages').css('background-color', '#5cb85c');
} else {
$('#itemImages').css('background-color', '#d9534f');
}
});
document.getElementById("frontImages").onchange = function () {
var x = document.getElementById('previewFrontImage');
x.style.display = 'block';
var reader = new FileReader();
reader.onload = function (e) {
document.getElementById("previewFrontImage").src = e.target.result;
};
reader.readAsDataURL(this.files[0]);
};
function previewImages() {
var $preview = $('#previewItemImages').empty();
if (this.files) $.each(this.files, readAndPreview);
function readAndPreview(i, file) {
var reader = new FileReader();
$(reader).on("load", function () {
$preview.append($("<img/>", {src: this.result, height: 100}));
});
reader.readAsDataURL(file);
}
}
$('#itemImages').on("change", previewImages);
I'm guessing that the conflict is between the html script and this
document.getElementById("frontImages").onchange = function ()
I also have a question how I can fix that there will be no small image when the image is too big
Your guess is correct, onchange is simply member variable of various elements, and thus
var uploadField = document.getElementById("frontImages");
uploadField.onchange = function() {
and
document.getElementById("frontImages").onchange = function ()
are setting this single variable (of frontImages), which will store one callback function at a time.
You could use addEventListener() instead, which maintains a list of event listeners, so there can be more than one. Modifying the lines to
var uploadField = document.getElementById("frontImages");
uploadField.addEventListener("change", function() {
and
document.getElementById("frontImages").addEventListener("change", function ()
will register both event listeners on frontImages, regardless of the order they are executed.
Side remark: when you have "nice" ids, document.getElementById() can be omitted, as elements with ids become variables (of window which is the global scope), and thus you could write frontImages.addEventListener(...). You still need the getter in various cases, like when a local variable shadows the id, or when it is not usable as variable identifier (like id="my-favourite-id" or id="Hello World")
I have a drag and drop container for uploading images. Something like the option that stackoverflow has in the editor. As you know, it works in two ways:
drag and drop an image
click on the container and then a window will be opened to choose an image
Now I'm exactly doing something like that:
// click
$('.upload_image').on('change', function () {
file = $(this)[0].files;
frm = $(this).closest('form');
addImageToInput();
return false;
});
// drag and drop
$(".container").on('drop dragdrop', function (e) {
file = e.originalEvent.dataTransfer.files;
frm = $(this).closest('form');
addImageToInput();
return false;
});
Also I have one more function for making a preview:
function addImageToInput() {
if ( file !== "" || frm !== "" ) {
let uploadFormData = new FormData(frm[0]);
uploadFormData.append("imageToUpload", file[0]);
readURL(frm.find(".upload_image")[0]);
formData = uploadFormData;
} else {
alert('something went wrong');
}
}
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
$('.modal-dropzone-img').html("<img src='" + e.target.result + "' class='upload_image_preview_img'/>");
}
reader.readAsDataURL(input.files[0]);
}
}
Anyway, the preview part works well when I attach an image by using "click" (browse) the image, and the preview part doesn't word (even no error throws) when I use drag and drop approach.
After some tests, I figured out, these aren't equal:
file = $(this)[0].files; // click approach
file = e.originalEvent.dataTransfer.files; // drag and drop approach
Any idea how can I make them equal? (in other word, I have to make the second one like the first one, because the first one is the working one)
I have modified the readURL method little bit to accept a file only, it can be drag drop or uploaded . Also addImageToInput() is changed accordingly
function addImageToInput() {
if ( file !== "" || frm !== "" ) {
let uploadFormData = new FormData(frm[0]);
uploadFormData.append("imageToUpload", file[0]);
readURL(file[0]);
formData = uploadFormData;
} else {
alert('something went wrong');
}
}
function readURL(input) {
if (input) {
var reader = new FileReader();
reader.onload = function(e) {
$('.modal-dropzone-img').html("<img src='" + e.target.result + "' class='upload_image_preview_img'/>");
}
reader.readAsDataURL(input);
}
}
here is a working fiddle
https://jsfiddle.net/153dp05q/
I am trying to get the file input preview working.
I have a jquery script which works fine when I call the function normally.
$('#images').on("change", previewImages);
This works.
But when I put the call to the same function differently like following
$('#images').on("change", function(){
previewImages();
});
This doesn't work.
I need to write an if else statement to call a different function on else.
Valid question
Reason: this happens because of this which refers to file element when you are using first approach but in case of second approach this is referring to window element in which it is called. So pass this to function and your question is solved.
$('#images').on("change", function(e) {
/* issue is with this */
previewImages(e, this);
});
var count = 0;
function previewImages(evt, cur) {
var $fileUpload = $("input#images[type='file']");
count = count + parseInt($fileUpload.get(0).files.length);
if (parseInt($fileUpload.get(0).files.length) > 7 || count > 6) {
alert("You can only upload a maximum of 6 files");
count = count - parseInt($fileUpload.get(0).files.length);
evt.preventDefault();
evt.stopPropagation();
return false;
}
$("#taskbar").css("height", "auto");
var $preview = $('#preview').empty();
if (cur.files) $.each(cur.files, readAndPreview);
function readAndPreview(i, file) {
// if (!/\.(jpe?g|png|gif|mp4)$/i.test(file.name)){
// return alert(file.name +" is not an image");
// }
var reader = new FileReader();
$('#preview img').addClass('img-responsive');
$(reader).on("load", function() {
$preview.append($("<img/>", {
src: this.result,
height: 100
}));
});
reader.readAsDataURL(file);
}
}
Create a prePreviewImages function, and use that in your first approach. Inside that function, use the if-statement and call previewImages() or your other function.
The following should do..
$('#images').change(function(e) {
if(e == "some condition"){ // if else goes here
previewImages();
}else {
SomeOtherFun();
}
});
Both ways seem to work for me on the JSFiddle. Are you sure it is not a
browser compatibility issue?
If not are you getting errors logged in the console under developer tools?
I am trying to create a function that will recursively try to reload an image until it either is successful, or a maximum amount of attempts is reached. I have created this function, but it doesn't work (is it due to the fact that the reference to the image has changed?):
function reload (image, URL, maxAttempts)
{
image.onerror = image.onabort = null;
if (maxAttempts > 0)
{
var newImg = new Image ();
newImg.src = URL;
newImg.onerror = image.onabort = reload (image, URL, maxAttempts - 1);
newImg.onload = function () {
newImg.onerror = newImg.onabort = null;
image = newImg;
}
}
else
{
alert ("Error loading image " + URL); /* DEBUG */
}
}
Which is used in the following manner:
var globalTestImage = new Image ();
reload (globalTestImage, "testIMG.jpg", 4);
Rather than it attempting to load "testIMG.jpg" four times, and waiting in between attempts, it instead tries to load it twice, and regardless of whether it was successful the second time around it will display the error message.
What am I doing there? More precisely, why is it acting the way it is, rather than retrying to load the image 4 times?
(function ($) {
var retries = 5; //<--retries
$( document).ready(function(){
$('img').one('error', function() {
var $image = $(this);
$image.attr('alt', 'Still didn\'t load');
if (typeof $image !== 'undefined') {
if (typeof $image.attr('src') !== 'undefined') {
$image.attr('src', retryToLoadImage($image));
}
}
});
});
function retryToLoadImage($img) {
var $newImg = $('<img>');
var $src = ($img.attr('src')) || '';
$newImg.attr('src', $src);
$newImg.one('error', function() {
window.setTimeout(function(){
if (retries > 0) {
retries--;
retryToLoadImage($newImg);
}
}, 1000); //<-retry interval
});
$newImg.one('load', function() {
return $newImg.attr('src');
});
}
})(jQuery);
Some code I wrote for the same case a while ago. Hope it helps you!
In the end I solve this issue in a simple (if inelegant) way:
try
{
canvas.getContext("2d").drawImage (testImage, 0, 0);
backgroundLoaded = true;
}
catch (err)
{
testImage = new Image ();
testImage.src = "placeholder.jpg";
}
The idea is that if an image failed to load, it will fail when rendering it on the canvas, producing an error. When such an error happens, we can create a new image and try again.
I'm having an issue with getting the dimensions of a newly updated image element.
I'm using FileReader to display a preview of an image file on screen.
Once the filereader and associated code has finished executing, I retrieve the new dimensions of the image element so I can adjust them accordingly.
On some browsers, the info doesn't get updated straight away and I need to include a delay before I can retrieve the new dimensions. This results in the new image being resized according to the previous image's dimensions, and not its own.
How can I be sure the new image has been fully loaded?
I would have thought FileReader().onloadend would have been sufficient but apparently not. I think this is executed once the fileReader has loaded it, not when the DOM has rendered it. (Am I right?)
Then I found this question, which suggests using a timeout of 1 millisecond. This works sometimes, but not always. It seems to be down to the speed the browser is rendering the image (more-so available resources rather than filesize). Do we have no other way of detecting a change in these parameters?
HTML
<img src="#.png" alt=""/>
<input id="fileInput" type="file" accept='image/*' onChange="loadIt()" />
JS
preview = getElementsByTagName('img')[0];
function loadIt() {
var imgReader = new FileReader();
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
imgReader.onloadstart = function(e) {
//
}
imgReader.onload = function (imgReaderEvent) {
if (isImage()) {
preview.src = imgReaderEvent.target.result;
//
}
else {
preview.src = 'error.png';
//
}
}
imgReader.onloadend = function(e) {
setImage();
setTimeout(function(){
setImage();
}, 1);
setTimeout(function(){
setImage();
}, 2000);
//
}
};
function setImage() {
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
//
};
You should call preview.onload or preview.onloadend on your image to detect that it has finished loading. You're also calling your events after you readAsDataURL The code should look like this
var preview=document.getElementsByTagName("img")[0];
function loadIt() {
var imgReader=new FileReader();
imgReader.onload=function(){
if (isImage()) {
preview.src = imgReader.result;
preview.onload=setImage;
} else {
preview.src = 'error.png';
//
}
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
}
function setImage(){
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
}
You're calling imgReader.readAsDataURL before your .onload and .onloadend is set.
I do not know what some of the variables are with-in the body of your setImage();however, start here:
function loadIt() {
var preview = getElementsByTagName('img')[0],
setImage = function () {
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
},
imgReader = new FileReader();
imgReader.onloadstart = function(e) {};
imgReader.onload = function (imgReaderEvent) {
if (isImage()) {
preview.src = imgReaderEvent.target.result;
}
else {
preview.src = 'error.png';
};
};
imgReader.onloadend = function(e) {setImage();};
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
};