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.
Related
I'm trying to write a service which reads the image file from an HTML input element. I want this service to return the HTML img object with the updated attribute from the read image file (the base64 string). My service is now this:
.service('ReadLocalImageService', [function () {
this.openLocalImage = function (file) {
var img = document.createElement("img");
var fileReader = new FileReader();
fileReader.onload = function (e) {
img.src = e.target.result;
};
fileReader.readAsDataURL(file);
return img.src;
};
}]);
The img.src in this case is returned empty, like this:
If I put a console.log(img.src) inside the fileReader.onload, it prints out what I want. It seems like the function openLocalImage is returning the img.src before e.target.result is assigned to it.
I couldn't manage to work this around nor find the correct topic about this problem. Could anyone help me solve this or explain me why it doesn't work?
Its because img was not loaded yet. Here is a solution
.service('ReadLocalImageService', [function () {
this.openLocalImage = function (file, callback) {
var img = document.createElement("img");
var fileReader = new FileReader();
fileReader.onload = function (e) {
img.src = e.target.result;
callback(img.src);
};
fileReader.readAsDataURL(file);
};
}]);
We will pass a callback function and receive img.src as its param. To use it
ReadLocalImageService.openLocalImage(myImage, function(imgSrc) {
// use imgSrc
});
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
so i want store the dataURl of a file outside the reader.onload function
but when i assign it to a variable hello and try to print it , it still remins undefined.
here is the code
<input type='file' accept='image/*' onchange='openFile(event)'><br>
<img id='output'>
<script>
var openFile = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){
var dataURL = reader.result;
var output = document.getElementById('output');
output.src = dataURL;
};
reader.readAsDataURL(input.files[0]);
var hello=reader.result;
console.log(hello);
console.log(reader.result);
};
</script>
but the same reader.result can be printed from inside the the on load function
i want a way to store the dataURL of the file outside the reader.onload function so that i can use it for future use anyway possible ?
Here is your script with some logging pointing out the order things will run:
var openFile = function(event) {
console.log("1. onchange triggered");
var input = event.target;
var reader = new FileReader();
console.log("2. Set handler for onload event");
reader.onload = function(){
console.log("5. onload handler called. Now the file is ready");
var dataURL = reader.result;
var output = document.getElementById('output');
console.log("6. Set img src to image");
output.src = dataURL;
};
console.log("3. Start reading file");
reader.readAsDataURL(input.files[0]);
console.log("4. Try to look at the file read result, even though the file has not finished being read yet...");
var hello=reader.result;
console.log(hello);
console.log(reader.result);
};
JS fiddle: https://jsfiddle.net/ncwv0ocL/1/
The problem is that readAsDataURL starts loading the file in the background, while the rest of your code executes. You can only get the result after the onload handler has been called.
One option to make it a bit clearer might be to do something like this:
var openFile = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = fileLoaded; // Tell the FileReader to call this function when the file is loaded
reader.readAsDataURL(input.files[0]);
// Code here should not depend on the state of the FileReader
};
var fileLoaded = function (event) {
var dataURL = event.target.result; // The event parameter gives us the target of the event (the FileReader)
var output = document.getElementById('output');
output.src = dataURL;
// Do your other stuff here with dataURL
console.log(dataURL);
};
One thing I like about this is that the code gets executes in the order it appears on the page :)
See it in action here: https://jsfiddle.net/ncwv0ocL/2/
The problem is trying to view the result after the reader is finished. The solution would be to call a function from our reader's onload that would provide any functionality we need, i.e. updating our output field.
var openFile = function(e) {
var input = e.target
var reader = new FileReader()
// Our doSomething function would do whatever is needed after we get our value.
// This allows us to dynamically update anything as opposed to having to check a value to see if it has been updated
var doSomething = function(dataURL) {
var output = document.getElementById('output')
output.src = dataURL
console.log(dataURL)
}
reader.onload = function() {
// Once we have the data, we pass it to our action that will control what we do with the result
doSomething(reader.result)
}
reader.readAsDataURL(input.files[0]);
}
So, our process becomes Upload File >> Read File >> Notify Application
Here is an example of the solution on CodePen
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 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);