FileReader reads only one file when multiple dropped - javascript

I am coding and form with and struggle tor ead each file. What i am getting is onlz one file being read.
Code below does log each iteration (console.log(i)), but does read and log only the last file, no matter what if read as dataURL or as Text
fileInput.on('change',function(){
var files= fileInput.prop('files');
console.log(files);
for(var i = 0; i < files.length; i++){
var reader = new FileReader();
console.log(i);
reader.onload = function(){
console.log(reader.result);
}
reader.readAsDataURL(files[i]);
}
});
I need each of multiple file to be logged in console. Thanks in advace

use let instead of var to properly scope the variable to the loop:
for (let i = 0; i < files.length; i++) { // Use let here
var reader = new FileReader();
console.log(i);
reader.onload = function() {
console.log(reader.result);
}
reader.readAsDataURL(files[i]);
}

You should use let instead of var for reader variable, since var is function scoped.

Didn't you forget the multiple attribute on the input element?

Related

Waiting for FileReader to complete before continuing

So I am starting to work with HTML5 and JS for the first time to do some experiments for a future game. I am using FileReader to read in a local text file that will represent a map, and using a script to return an array of arrays based on the text read in.
The problem is, I am having trouble with undefined variables.. because my code is executing before FileReader is able to read in the input file and do its processing. This is my block that reads in:
document.getElementById('input').addEventListener('change', function() {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function(e) {
let map = readMap(e.target.result);
}
reader.readAsText(file);
}, false);
readMap() is an external function that simply takes the raw text and returns a 2d array based on it. This all works great.. and I tested that by logging inside of the readMap function. The issue is that I am referencing this 'map' variable later on in this file in order to read it, render it, etc. I immediately get 'Uncaught ReferenceError: map is not defined' when loading my code. This makes perfect sense... since the above block did not yet get to execute.. as it is still waiting on the user to select an input file.
Here is one of the few functions that need access to the 'map' later on in the code:
function drawMap() {
let x = 0;
let y = 0;
for(var i=0; i<map.length;i++) {
for(var j=0; j<map[i].length;j++) {
if(map[i][j] === 1) {
ctx.fillRect(x,y,BLOCK_SIZE,BLOCK_SIZE);
x+=BLOCK_SIZE;
}
else if(map[i][j] === 'S') {
player.x = x;
player.y = y;
x+=BLOCK_SIZE;
}
else {
x+=BLOCK_SIZE;
}
}
x=0;
y+=BLOCK_SIZE;
}
}
Im not sure if that helps, but I just wanted to give an example of how I need to use this array.
Being fairly new to JS, I am really not yet finished wrapping my head around the idea of onLoads and callbacks... but my feeling is that they are the way to go about making this work. I assume I need to somehow tell the rest of my code not to execute until the 'map' object is finished being created.
I hope that was clear. Any help is appreciated!
Call the function drawMap() or any other function only after you have received the data, thus within reader.onload callback, if you want to access this map later, make map variable global e.g.:
var map;
document.getElementById('input').addEventListener('change', function() {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function(e) {
map = readMap(e.target.result);
drawMap();
}
reader.readAsText(file);
}, false);
Or you can also pass map variable to drawMap function:
document.getElementById('input').addEventListener('change', function() {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function(e) {
let map = readMap(e.target.result);
drawMap(map);
}
reader.readAsText(file);
}, false);
function drawMap(map) {
let x = 0;
let y = 0;
for(var i=0; i<map.length;i++) {
for(var j=0; j<map[i].length;j++) {
if(map[i][j] === 1) {
ctx.fillRect(x,y,BLOCK_SIZE,BLOCK_SIZE);
x+=BLOCK_SIZE;
}else if(map[i][j] === 'S') {
player.x = x;
player.y = y;
x+=BLOCK_SIZE;
} else {
x+=BLOCK_SIZE;
}
}
x=0;
y+=BLOCK_SIZE;
}
}
there is also FileReaderInstance.onloadend event
reader.onloadend = () => drawMap()

Reading and comparing contents of a file in javascript

I am trying to implement a Search Function for my app.
The search needs to involve several files that are in the server side.
So, I thought about reading each file to check if the search term is contained in them.
Code:
function search()
{
var term = document.getElementById("search-input").value;
var fileInput = document.getElementById("helpfiles");
var fileList = fileInput.files;
for (var i = 0; i < fileList.length; i++)
{
var reader = new FileReader();
reader.readAsText(fileList[i]);
reader.onload = function(e)
{
var text = reader.result;
alert(text) // test purpose only
if(text.indexOf(term) !== -1) // PROBLEM HERE
alert(fileList[i].name)
}
}
}
Until the code line:
alert(text)
everything works well.
The problem happens in the if-statement that it simply does not work as expected.

Array.push not updating an array variable

Here is the code I am working on:
<!--HTML Code for referencing the file -->
<input type="file" name="file" id="file">
<script>
var store = [];
document.getElementById('file').onchange = function(){
var file = this.files[0];
var reader = new FileReader();
// Define the body of reader function
reader.onload = function(progressEvent){
// By lines
var lines = this.result.split('\n');
for(var line = 0; line < lines.length; line++){
// Store it in an array
store.push(lines[line]);
//console.log(store.length); // This line on being uncommented
// shows that store is being modified. The values getting printed
// are 1,2,3, ...... upto 16 (length of the input file)
}
};
// Read the file and store it in the var "store"
reader.readAsText(file);
console.log(store.length); // The problem appears here!!!!!
};
</script>
The problem is, even after choosing a file containing 16 sample numbers, the console prints the store.length value as 0. Why is the push command not affecting the var "store" ?
You're setting up an event handler on the onchange property, but you're doing a console.log(store.length) outside, so you will never get the results you expect that way.
The event handler function will be triggered when the value of your element with id "file" changes, so you need to print the length of the store, inside the function, like this:
document.getElementById('file').onchange = function(){
var file = this.files[0];
var reader = new FileReader();
// Define the body of reader function
reader.onload = function(progressEvent){
// By lines
var lines = this.result.split('\n');
for(var line = 0; line < lines.length; line++){
// Store it in an array
store.push(lines[line]);
//console.log(store[line]);
}
console.log(store.length);
};
I would recommend also declaring the store as local to that function, that way you'll always get a brand new array, otherwise you need to manually re-initialize it or empty it before you start adding things to it or on subsequent change events, your "store" array will be filled with everything from the previous changes.
Makes sense?
FileReader is asynchronous. You either want to use FileReaderSync or do this:
var store = [];
document.getElementById('file').onchange = function() {
var file = this.files[0];
var reader = new FileReader();
// Define the body of reader function
reader.onload = function(progressEvent) {
// By lines
var lines = this.result.split('\n');
for (var line = 0; line < lines.length; line++) {
// Store it in an array
store.push(lines[line]);
}
};
reader.onloadend = function() {
console.log(store.length);
};
// Read the file and store it in the var "store"
reader.readAsText(file);
};
<input type="file" name="file" id="file">
The onload event of the FileReader is asyncrhonous. Which means it's not executed in the natural flow of the program.
To check the final length of the store variable, you should do this:
var store = [];
document.getElementById('file').onchange = function(){
var file = this.files[0];
var reader = new FileReader();
// Define the body of reader function
reader.onload = function(progressEvent){
// By lines
var lines = this.result.split('\n');
for(var line = 0; line < lines.length; line++){
// Store it in an array
store.push(lines[line]);
}
// Correctly reads the final length of the store variable.
console.log(store.length);
};
reader.readAsText(file);
};
Hope it helps.

Getting the content of each file in multiple file input using jquery

I need to fetch the content of each file in multiple file input using jquery and based on the file content i need to do some modifications in my page. Here is the code I have written to do the same. Here what is happening is If I select 3 files I am getting the content of 3rd file alone. If I use the index number instead of looping I am able to get the contents But If I use looping I am getting the last files content alone. Could someone explain me whats wrong with it ?
<input type="file" name="xsd" id="xsd" multiple="multiple">
$('#xsd').change(function(){
input = document.getElementById('xsd');
for(var i = 0; i < input.files.length ; i++)
{
file = input.files[i];
fr = new FileReader();
fr.readAsText(file);
fr.onload = function(e) {
var filecontent = fr.result;
// My logic here
}
}
});
Your problem is that the onload function is getting it's "fr" from a closure.
You can create a separate closure for each of the onload-callbacks by using an immediately-invoked anonymous function like this:
$('#file').change(function(){
input = document.getElementById('file');
for(var i = 0; i < input.files.length ; i++)
{
(function(i) {
var file = input.files[i];
var fr = new FileReader();
fr.onload = function(e) {
var filecontent = fr.result;
// My logic here
}
fr.readAsText(file);
})(i);
}
});

jQuery loop on multiple input.files

I need to loop this on a multiple file input:
var reader = new FileReader();
reader.onload = function (e) {
$('#pprev_0')
.attr('src', e.target.result);
};
reader.readAsDataURL(input.files[0]);
I tried this, but it does not work:
var fileCount = 0;
$("input[name='files[]']").each(function() {
var reader = new FileReader();
reader.onload = function (e) {
$('#pprev_'+fileCount)
.attr('src', e.target.result)
.css("display","block");
};
reader.readAsDataURL(input.files[fileCount]);
fileCount++;
});
alert() on fileCount output is a one time 0 on multiple file selection. no further alerts. If I take numbers instead of the fileCount var in code, it works at position. r.g. input.files[2] ...
Any idea?
When you do this: $("input[name='files[]']").each(function() { you are actually getting any elements that match the selector. In this case, you get your single multi file input (which is why you only see 1 alert. What you want to do is iterate over the files.
This page has code to do pretty much exactly what you want. I recommend you check it out:
http://www.html5rocks.com/en/tutorials/file/dndfiles/
To apply it to your situation, you would do something like this:
var files = $('#files')[0].files; //where files would be the id of your multi file input
//or use document.getElementById('files').files;
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
reader.onload = function (e) {
$('#pprev_'+fileCount)
.attr('src', e.target.result)
.css("display","block");
};
reader.readAsDataURL(f);
}

Categories