I have the following problem.
I have an upload form for multiple files. The upload process goes fine. The problem is related with the FileReader() result. As I am uploading multiple files(images) I need to create corresponding thumbs when the upload is finished.
files = e.target.files;
for (var i = 0; i < files.length; i++) {
//ajax request goes here
var reader = new FileReader();
reader.onload = (function (e) {
var img = document.createElement('img');
img.file = e;
img.className = 'thumbs_';
img.src = e.target.result;
//Every image has a wrapper div with the id 'nDv0','nDv1','nDv2' etc.
document.getElementById('nDv' + i).appendChild(img);
})(e);
reader.readAsDataURL(files[i]);
//request sent
}
If I remove the closures around the anonymous function, i's value will be anything when the for loop exits.
For example, if there are 3 files, i's value will be 3 and the results will be appended to the last wrapper div and images will be displayed.
With closures every image is getting appended to the corresponding div, but the images won't be displayed as the returned result is undefined.
So, how can I append every thumb to its corresponding div?
You has a logic error:
reader.onload = (function (e) {
//onload code
//inside function e is event from outside
})(e);//e is event from upper code
And the i will be equal to files.length because onload handler is async.
So you must change your onload handler to:
reader.onload = function (index) {
var img = document.createElement('img');
img.className = 'thumbs_';//it's right className?
img.src = this.result;//result is dataURL
document.getElementById('nDv' + index).appendChild(img);
}.bind(reader, i);
Related
I am doing a simple file text upload using FileReader.
var filesInput = document.getElementById("txtImport");
for (var i = 0; i < filesInput.files.length; i++) {
current = filesInput.files[i];
var reader = new FileReader();
reader.onload = function(file) {
return function(e) {
console.log('e', e) // not logging
}
}(current)
}
Upon reading FileReader onload with result and parameter, I need to use closure so as to not lose the scope inside the loop. When I click the button to trigger the upload, why is the log not coming up? Why isn't the function firing?
You need to call one of the readAs___ methods of the FileReader:
https://developer.mozilla.org/en-US/docs/Web/API/FileReader
If you're reading multiple files parallel, you need a separate reader for each.
Also, the parameter the event handler receives is an event object, not the contents of the file. Those will be in reader.result.
for (var i = 0; i < filesInput.files.length; i++) {
let reader = new FileReader();
reader.onload = function(event) {
console.log(reader.result);
}
reader.readAsText(filesInput.files[i]);
}
I'm writing what I think is some pretty routine javascript. However I'm having an issue I can't seem to resolve. I'm looping through an array and when it reaches the point of a function being called, the loop breaks. If I take the function out the loops runs to completion. I can't seem to figure it out.
for (i=0;i<response.items.length;i++) {
console.log("cover: ", decodeURIComponent(response.items[i].coverPhotoPath));
previewAlbum(decodeURIComponent(response.items[i].coverPhotoPath));
}
The code for the function being called is...
function previewAlbum(file) {
console.log("preview", file);
var galleryId = "photo";
var gallery = document.getElementById(galleryId);
var img = document.createElement("img");
img.style.cssText = 'width:200px;height:200px;';
img.src = file;
gallery.appendChild(img);
// Using FileReader to display the image content
var reader = new FileReader();
reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
reader.readAsDataURL(file);
}
Each piece of code works on it's own. But when put together the loop breaks. Any ideas?
I've a situation where I need to work on a user-provided image with two different functions.
Get user input
Process the image and put it back processed
note: code is incomplete and shortened for brevity. Please don't point out the irrelevant.
1. Get user input
var fReader = new FileReader();
fReader.onload = function(e){
image = new Image();
image.onload = function(){
//BEGIN OF RELEVANT SECTION
processOnCanvasAndBack(image, myCallbackToProceed);
};
image.src = e.target.result;
};
fReader.readAsDataURL(src);
2. Process the image and put it back processed
function processOnCanvasAndBack(image) {
var canvas = $('<canvas></canvas>');
canvas.draw(image);
canvas.doSomeStuffLikeRotatingAndColorBalance();
//BEGIN OF RELEVANT SECTION
image.onload = function() {
myCallbackToProceed();
};
image.src = canvas.toDataURL();
}
Problem
The image.onload from 1. calls the function as expected but when I call the second image.src from 2 the first image.onload gets called again, which in turns calls 2 again and.... booooom, infinite loop (console spits too many recursions)
I tried to reset the first call with image.onload = function(){}; in various points, but it doesn't fix the issue (no more recursion, but the functions just stop being called). Right now I'm out of ideas :-(
I would suggest creating two image objects. One for the source image, and a second for the transformed / target image. You avoid mutating existing state and causing infinite loops by repeatedly setting the .src of the same image object in the onload events. Avoid mutating state whenever possible. I would also suggest using the var keyword to define the variables locally instead of in the global scope.
var fReader = new FileReader();
fReader.onload = function(e){
var sourceImage = new Image();
var targetImage = new Image();
sourceImage.onload = function() {
//BEGIN OF RELEVANT SECTION
processOnCanvasAndBack(sourceImage, targetImage, myCallbackToProceed);
}
sourceImage.src = e.target.result;
};
fReader.readAsDataURL(src);
function processOnCanvasAndBack(sourceImage, targetImage, callback) {
var canvas = $('<canvas></canvas>');
canvas.draw(sourceImage);
canvas.doSomeStuffLikeRotatingAndColorBalance();
// BEGIN OF RELEVANT SECTION
targetImage.onload = function() {
callback();
};
targetImage.src = canvas.toDataURL();
}
I got a Jquery function that read a FilesList and display in an IMG html object the image.
function load_images(files) {
for (var i = 0; i < files.length; i++) {
// Validate the image type
if(validate_file(files[i])) {
var reader = new FileReader();
reader.onload = function(e) {
$(".upload_thumbnails").append(render_thumb(e.target.result, i)); // Return a string with the img object
};
}
reader.readAsDataURL(f);
}
}
But my images are not append in the sequential order of the fileList. The fileList (var files) is implement by an multiple input file html object.
Do you have any idea ?
The method readAsDataURL is asynchronous meaning that your loop will create a lot of requests to load data, but because the method is asynchronous there is not way to to know in which order the onload callback will be called. The behaviour is non-deterministic.
This could be solved by storing all the elements in an array along with their index and then actually rendering out all the images when they have all loaded completely.
Another alternative is creating a placeholder div when the requests is started and capture it in the closure of the onload callback. Then you could append the image to that div, this would cause the behaviour you want.
Like this:
function load_images(files) {
for (var i = 0; i < files.length; i++) {
// Validate the image type
if(validate_file(files[i])) {
var reader = new FileReader(),
div = $("<div></div>");
$(".upload_thumbnails").append(div);
reader.onload = function(e) {
div.append(render_thumb(e.target.result, i)); // Return a string with the img object
};
}
reader.readAsDataURL(f);
}
}
I am using HTML5 file API to get the width of an image.
Its working, and the console.log is outputting the correct amount.
I need to save the value to the variable fileWidth so I can access it outside the function. I have created an empty variable outside the function, and expected it to be updated with the alue inside the function, but whatever I try fails.
Here is my code:
var fileWidth;
var reader = new FileReader;
reader.onload = function() {
var img = new Image;
img.onload = function() {
fileWidth = img.width;
console.log(fileWidth);
};
img.src = reader.result;
};
reader.readAsDataURL($('#submission-file')[0].files[0]);
Can anyone see why the variable isn't being updated?
Edited Code:
var fileWidth;
var reader = new FileReader;
reader.onload = function() {
var img = new Image;
img.src = reader.result;
};
reader.onloadend = function() {
fileWidth = img.width;
};
reader.readAsDataURL($('#submission-file')[0].files[0]);
console.log(fileWidth);
You're setting fileWidth in an asynchronous callback, this method isn't guaranteed to have executed prior to your accessing the variable.
Hint
Try putting an alert in your callback and an alert right before you access the variable. See which alert is presented first.