Array.push not updating an array variable - javascript

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.

Related

FileReader reads only one file when multiple dropped

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?

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.

File reader execute multiple times in javascript

I'm trying to load images in to page for preview before uploading with javascript.
I have following code:
holder.onclick = function(event) {
function chooseFile(name) {
var chooser = $(name);
chooser.unbind('change');
chooser.change(function(evt) {
function loadFile(file, callback) {
var reader = new FileReader();
(reader.onload = function(file) {
console.log(f);
var output = document.createElement('input');
output.type = 'image';
output.classList.add('image-responsive');
output.classList.add('col-xs-12');
output.name = f;
output.id = f;
output.src = reader.result;
var x = document.getElementById('OrigName');
x.appendChild(output);
return callback(output);
})(f = file.name);
reader.readAsDataURL(file);
}
for (var i = 0; i < evt.target.files.length; i++) {
console.log(i);
var file = evt.target.files[i];
loadFile(file, function(output) {
// console.log(output);
});
}
});
chooser.trigger('click');
}
chooseFile('#fileDialog');
}
Problem is, whenever i load image, code inside reader.onload method execute twice, and in console i 2x result of console.log(f) and 2 errors that 'localhost/null is not found'.
When i remove (f=file.name), script execute as it should be, but then i don't have file.name variable inside reader scope.
EDIT:
Here's JSFiddle of my problem:
https://jsfiddle.net/onedevteam/udmz34z0/6/
Can someone help me fix this?
Problem is, whenever i load image, code inside reader.onload method execute twice
This is because in your code you have this.
(reader.onload = function(file) {
//...
//...
})(f = file.name); // <---- self executing function.
reader.readAsDataURL(file);
Here you are using "Self Executing function" for the reader.onload, So what happens is it will execute once when it hits this line of code, And again when reader.readAsDataURL(file) has completed reading. So remove the "self executing function " and you logic will run only once
When i remove (f=file.name), script execute as it should be, but then i don't have file.name variable inside reader scope.
to get the file name just add it in a variable and use it like this.
var fileName = file.name;
reader.onload = function() {
//...
//...
output.name = fileName ;
output.id = fileName ;
}; // <-- self executing function REMOVED
Also I feel there is no need to save the file name into a variable because the variable file passed into function is sufficient to get the job done. So below would be the final code as per my suggestion.
function loadFile(file, callback) {
var reader = new FileReader();
reader.onload = function() {
console.log(file.name); //
var output = document.createElement('input');
output.type = 'image';
output.classList.add('image-responsive');
output.classList.add('col-xs-12');
output.name = file.name; //
output.id = file.name; //
output.src = reader.result;
var x = document.getElementById('OrigName');
x.appendChild(output);
return callback(output);
};
reader.readAsDataURL(file);
}
You're calling reader.onload at least twice. You have this function inside another function loadFile(), and you call it immediately (which is why you only see this behavior when you have (f=file.name) there), but then also inside the chooser.change function you have that for-loop that calls loadFile(). Perhaps ou could set the file.name variable somewhere other than (f=file.name) and then make reader.onload not execute automatically.
The way you have your code structured, your onload handler will be executed twice, once when you define it, and then again when the "load" event fires. When you wrap a function definition inside parens:
(reader.onload = function (file) { ... })(f = filename)
you're saying "define this function and execute it immediately."
What you really want is a function that returns a function, like this:
function makeOnLoadHandler (filename) {
return function (file) {
// ... do whatever you need to with file and filename
};
}
reader.onload = makeOnLoadHandler(someFileName);
The outer function, makeOnLoadHandler(), creates a closure around your filename variable, and when the inner function handles the reader's load event, it will see the filename that you passed in when you called makeOnLoadHandler.

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);
}
});

Javascript File Reader

I may just not be understanding the file reader api, but
When I try to run:
for (var i = 0, f1, f2; f1 = files[sorted_index[i]], f2 = files[sorted_index[i+1]]; i=i+2) {
var file_one;
var file_two;
if(f1.size < f2.size){
file_one = f1;
file_two = f2;
} else {
file_one = f2;
file_two = f1;
}
var file_one_contents;
var file_two_contents;
var reader = new FileReader();
reader.readAsText(file_one);
reader.onload = readSuccess;
function readSuccess(evt){
file_one_contents = evt.target.result;
}
var reader = new FileReader();
reader.readAsText(file_two);
reader.onload = readSuccess2;
function readSuccess2(evt2){
file_two_contents = evt2.target.result;
}
console.log(file_one_contents);
console.log(file_two_contents);
The console log only contains undefined in it.
The goal of the script it two read in two CSVs and take the data from the pair of files and do some computations.
Thanks!
The API is asynchronous. The "success" functions are called when the operation completes, and that won't be immediate.
Move your console.log() calls to inside the handler functions.
edit — If you need to wait to start doing stuff until both files are ready, you can do something like this:
var countdown = 2;
var reader = new FileReader();
reader.readAsText(file_one);
reader.onload = readSuccess;
function readSuccess(evt){
file_one_contents = evt.target.result;
countdown--;
if (countdown === 0) go();
}
var reader = new FileReader();
reader.readAsText(file_two);
reader.onload = readSuccess2;
function readSuccess2(evt2){
file_two_contents = evt2.target.result;
countdown--;
if (countdown === 0) go();
}
There are more sophisticated ways to do it, of course, but that simple trick just waits until the counter is zero before calling "go()", which represents the function that'd work on processing the files.
I had a similar problem which solved the file read waiting by using ".onloadend" instead of "onload". In the code below x is bound to a "div" element
reader.onloadend = function (evt) {
x.innerHTML = evt.target.result;
}
With "onload" it was all undefined.

Categories