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

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

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?

How can I read a file from an HTML input with js-xlsx?

I have an angular application where I am trying to read and parse a .xlsx file resorting to the js-xlsx JavaScript library. However I am having trouble opening the file on the JavaScript side.
On my html I have a simple input of type file that opens a file chooser where the user can choose an appropriate file. I had trouble using angular directives to send the file to a function on my controller, because ng-change would not update when the user chose a file only when the button of the input is pressed. I ended up having to resort to a mixture of plain old JavaScript together with some angular by adding 'onchange="angular.element(this).scope().handleFile(this)"' to my input.
add-quotation.html:
<div class="container-fluid" ng-controller="addQuotationController">
...
<input type="file" id="file" class="" onchange="angular.element(this).scope().handleFile(this)">
...
</div>
This solved my problem of not being able to send the file from the HTML to the JavaScript side of things. However, I'm having trouble opening the file. I have tried many examples from the official documentation but I haven't succeeded in making it work. This is my current code:
add-quotation.component.js:
$scope.handleFile = function(e) {
var files = e.target.files;
var i,f;
for (i = 0, f = files[i]; i != files.length; ++i) {
var reader = new FileReader();
var name = f.name;
reader.onload = function(e) {
var data = e.target.result;
var workbook = XLSX.read(data, {type: 'binary'});
/* DO SOMETHING WITH workbook HERE */
};
reader.readAsBinaryString(f);
}
}
I tried to debug and found out that the file does indeed get into the method but then an exception occurs when trying to access "e.target.files;"
I'm completely lost in how to fix this and the examples that I've seen are of no help. What am I doing wrong?
You are looking for wrong object rather you should be using e.files. This is because e represents the <input> element; aka the value of this in your onchange attribute: onchange="angular.element(this).scope().handleFile(this)"
$scope.handleFile = function(e) {
console.log(e.files);
var files = e.files;
var i,f;
for (i = 0, f = files[i]; i != files.length; ++i) {
var reader = new FileReader();
var name = f.name;
reader.onload = function(e) {
var data = e.target.result;
var workbook = XLSX.read(data, {type: 'binary'});
/* DO SOMETHING WITH workbook HERE */
};
reader.readAsBinaryString(f);
}
}
you don't need FileReader(), instead use Blob.arrayBuffer()
$scope.handleFile = async function(e) {
var workbook = XLSX.read(await e.files.arrayBuffer(), {type: 'binary'});
// .....
}

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.

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