I would like to ask you, if it is possible to iterate through list of file inputs and save the results in one array. Here is bit of my code.
Also I use AngularJS if it helps...
HTML
<input type="file" id="file1">
<input type="file" id="file2">
<button id="saveBtn">Save</button>
JAVASCRIPT
results = []; // array for storing results
/*file inputs*/
inputs = [document.getElementById('file1'), document.getElementById('file2')];
function readFile() {
for (var i = 0; i < inputs.length(); i++) {
if (inputs[i].files && inputs[i].files[0]) {
var FR = new FileReader();
FR.onload = function (event) {
results[i] = event.target.result; //array where I would like to store results
};
FR.readAsDataURL(inputs[0].files[0]);
}
}
}
//here I would like to write down all results
var btn = document.getElementById('saveBtn');
btn.onclick = function() {
readFile();
for(var i=0; i < inputs.length(); i++) {
console.log(results[i]);
}
}
When I run this code, as result I get 'undefined'.
Do you guys have any ideas how to achieve this? Thank you
Besides the point that Niek Vandael makes in his answer; the fact that you are trying to show information before it has completed loading, there are a few other issues with your code.
input.lengths()
should be
input.lengths
lengths it's not a method. That causes an error when I test the code (in Chrome).
You also read the same data over and over;
FR.readAsDataURL(inputs[0].files[0]);
should probably be
FR.readAsDataURL(inputs[i].files[0]);
So, here's another take on it. I added a couple of vars to keep track of items loaded and how many there are to load, then call the function to display the data once it has been loaded.
results = []; // array for storing results
/*file inputs*/
inputs = [document.getElementById('file1'), document.getElementById('file2')];
//here I would like to write down all results
var btn = document.getElementById('saveBtn');
var inputCount;
var filesLoaded = 0;
function readFile() {
inputCount = Number(inputs.length);
for (var i = 0; i < inputCount ; i++) {
if (inputs[i].files && inputs[i].files[0]) {
var FR = new FileReader();
FR.onload = function (event) {
results.push(event.target.result); //array where I would like to store results
filesLoaded++;
if (filesLoaded == inputCount) {
showResult();
}
};
FR.readAsDataURL(inputs[i].files[0]);
}
}
}
btn.onclick = function () {
readFile();
}
function showResult() {
for (var i = 0; i < inputs.length ; i++) {
console.log(results[i]);
}
}
There are a few more things to think about, such as validating that files have been selected etc, but I guess it's kind of out of the scope here.
onLoad gets executed when the FileReader has loaded, so after you write your log statements.
Try this:
https://jsfiddle.net/s17Lmc21/1/
results = []; // array for storing results
/*file inputs*/
inputs = [document.getElementById('file1'), document.getElementById('file2')];
function readFile() {
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].files && inputs[i].files[0]) {
var FR = new FileReader();
FR.onload = function (event) {
results[i] = event.target.result; //array where I would like to store results
console.log(results[i]);
};
FR.readAsDataURL(inputs[0].files[0]);
}
}
}
//here I would like to write down all results
var btn = document.getElementById('saveBtn');
btn.onclick = function() {
readFile();
}
Related
I am trying to do sync call using tableau.
var checkLen = $s_filter_i.length;
for (i = 0; i < checkLen; i++) {
var filterValfscr = $s_filter_i[i].VALUE;
Send_Tablo(filterValfscr);
}
When call this function Send_Tablo(filterValfscr) it runs the below code.
But the problem is before I get response form getSummaryDataAsync() it comes out of the function recalls Send_Tablo(filterValfscr) again I get the latest request data instead of first data request.
function Send_Tablo() {
var filter_indx = JSON.parse(window.localStorage.getItem('filter_indx'));
var arry = [];
for (var i = 0; i < filter_indx.s_filter_i.length; i++) {
Attr_lab_name = filter_indx.s_filter_i[i].ATTRIBUTELABEL;
arry.push(filter_indx.s_filter_i[i].VALUE);
}
currentViz.getWorkbook().changeParameterValueAsync('Attribute_Label', filterValfscr, Attr_lab_name, arry);
alert(filterValfscr);
var fScr_data;
sheet = currentViz.getWorkbook().getActiveSheet();
sheet.getSummaryDataAsync(options).then(function (t) {
data = t.getData();
console.log("Data", data);
frscr_demo();
});
function frscr_demo() {
//var fScr_data;
currentViz.getWorkbook().getActiveSheet().applyFilterAsync(Attr_lab_name, arry, tableau.FilterUpdateType.REPLACE);
sheet = currentViz.getWorkbook().getActiveSheet();
sheet.getSummaryDataAsync(options).then(function (t) {
fScr_data = t.getData();
console.log("FSCR", fScr_data);
var aa = $(fScr_data).length;
});
}
}
What I am try to achieve is Send_Tablo() should run all the Async function first before running the second iteration of Send_Tablo() from the for loop.
Do let me known what I am doing wrong? Thanks in advance.
I'm writing a script that enables me to create an object that uploads files and that should have methods to get properties such as the total size of the files uploaded, let me show you:
function FileUploader = function (to){
let html = "some html with the form...";
to.append(html);
let input = 'someSelector...';
let allSizes = [];
let allSrcs = [];
let totalSize = 0;
input.on('change', function (){
//some validation
let data = new FormData();
//for loop to append the input files
let request = createRequest(); //createRequest returns a request...
request.addEventListener("load", function (evt){
for( let i = 0; i<input.files.length; i++){
totalSize+= input.files[i].size;
allSizes.push(input.files[i].size);
}
let response = JSON.parse(e.currentTarget.responseText);
for(let i = 0; i<response.length; i++){
allSrcs.push(response[i]);
}
alert("Ok");
);
//other request handlers
request.open("POST", 'someLocalPath');
request.send(data);
});
}
Uploader.prototype.getSrcs= function (){
//the problem comes here, I can't pass the value of any variable in the object
}
I have tried transforming the let variables into this assignments like this:
function FileUploader = function (to){
let html = "some html with the form...";
to.append(html);
let input = 'someSelector...';
this.allSizes = [];
this.allSrcs = [];
this.totalSize = 0;
input.on('change', function (){
//some validation
let request = createRequest(); //createRequest returns a request...
request.addEventListener("load", function (evt){
for( let i = 0; i<input.files.length; i++){
this.totalSize+= input.files[i].size;
this.allSizes.push(input.files[i].size);
}
let response = JSON.parse(e.currentTarget.responseText);
for(let i = 0; i<response.length; i++){
this.allSrcs.push(response[i]);
}
alert("Ok");
);
});
}
In the last case I get undefined errors such as cannot read property push of undefined.
I really hope you can help me, thank you a lot!
For everyone looking for a quick solution easy to understand here's a solution:
function Person() {
var that = this;
that.age = 0;
setInterval(function growUp() {
// The callback refers to the `that` variable of which
// the value is the expected object.
that.age++;
}, 1000);
}
That's the most basic example I found. I hope it helps you.
In this W3schools example, console.log on the input element reveals a FileInput object:
FileList {0: File, 1: File, length: 2}
How can I work with this? The example demonstrates accessing the file, but every time a user selects new files, the old files disappear. How can I create a new empty FileList and copy it over, so that a user can add more files to the FileList?
I tried this, but it results in two FileList objects, rather than one FileList with all the files:
var fileStore = x.files;
function myFunction(){
var txt = "";
if ('files' in x) {
if (x.files.length == 0) {
txt = "Select one or more files.";
} else {
fileStore += x.files;
console.log(x.files);
console.log(fileStore);
Untested, but this should work
var fileStore = [];
function myFunction(){
var txt = "";
if ('files' in x) {
if (x.files.length == 0) {
txt = "Select one or more files.";
} else {
fileStore.push.apply(fileStore,x.files);
console.log(x.files);
console.log(fileStore);
More on Function::apply
More on Array::push
It is not possible to add File objects to FileList. You can use FormData to append Files to a single object.
var data = new FormData();
document.querySelector("input[type=file]")
.addEventListener("change", function(event) {
for (var i = 0, files = event.target.files; i < files.length; i++) {
data.append("file-" + [...data.keys()].length, files[i], files[i].name)
}
})
An array is fine for holding onto the File instances, but FormData is better if you want to upload them somewhere. If you want to log out or view the FormData, turning it into a Map is an option. Keep in mind that FormData is iterable.
var formData = new FormData();
var index = 0;
function onDrop(event)
{
var dt = event.dataTransfer;
var files = dt.files;
var count = files.length;
output("File Count: " + count + "\n");
for (var i = 0; i < files.length; i++) {
formData.append(files[i].name, files[i]);
}
}
function output(text)
{
document.getElementById("output").textContent += text;
console.dir(new Map(formData));
}
See this JSBin.
it is possible to add files using the datatransfer class
export const makeFileList = files => {
const reducer = (dataTransfer, file) => {
dataTransfer.items.add(file);
return dataTransfer;
}
return files.reduce(reducer, new DataTransfer()).files;
}
From a .csv file I need to build a tree structure using three columns below.
Column state should be the parent node, id is a child node of state and ndi is a child of id node.
Currently my program can read the .csv file and store it in a two dimensional array.
Here is my code: Link to .csv file
<body>
<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>
<script>
function handleFileSelect(evt) {
var files = evt.target.files;
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
var string = e.target.result;
console.log(string);
var array1=string.split("\n");
alert(array1.length)
var array2 = new Array();
for(var i=0; i< array1.length; i++){
array2[i] = array1[i].split(",");
}
//completed upto saving as 2D array
};
})(f);
reader.readAsText(f);
}
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>
I want to build a tree structure out of it.
This should do it, replace your second for with the code below:
// We cannot define our own keys for Javascript arrays, so we are using Object
var result = new Object();
var salesIndex = 8;
var idIndex = 0;
var ndiIndex = 7;
for(var i=0; i< array1.length; i++){
// array containing all line's columns
var columns = array1[i].split(",");
// especific columns that is of our interest
var rowSale = columns[salesIndex];
var rowId = columns[idIndex];
var rowNdi = columns[ndiIndex];
// If sale key doesn't exists in the array, add it
if (!(rowSale in columns)) {
result.rowSale.rowId = new Array();
result.rowSale.rowId.push(rowNdi);
} else if (!(rowId in columns.rowSale)) {
// If id key doesn't exists in the array, add it
result.rowSale.rowId = new Array();
result.rowSale.rowId.push(rowNdi);
} else if (!columns.rowSale.rowId.indexOf(rowNdi)) {
// If ndi isn't in the array, add it
result.rowSale.rowId.push(rowNdi);
}
}
If I did'nt missunderstand you, this should do the trick:
function buildTree(input) {
var output = {};
for (var i in input) {
var state = input[0];
var id = input[1];
var ndi = input[2];
if (output[state] === undefined) output[state] = {};
if (output[state][id] === undefined) output[state][id] = [];
output[state][id].push(ndi);
};
return output;
};
var arrayTest;
function handleFiles(files) {
arrayTest = new Array();
for(var i = 0; files[i]; i++) {
var reader = new FileReader();
reader.onload = function(e) {
var binary = e.target.result;
var parentSelector = '#output_' + i;
$(parentSelector).html(binary);
arraytest.push({ 'bin' : binary, 'parentSelector' : parentSelector });
};
reader.readAsBinaryString(files[i]);
}
}
function buttonClick() {
var files = [file1, file2];
handleFiles(files);
console.log(arrayTest); // I got the objects inserted at async function here, length != 0
console.log(arrayTest.length); // 0
console.log(arrayTest[0]); //undefined
// accesing any member of arrayTest returns undefined
}
FireFox Console output.
The code above shows a Js that converts files into binary string that is ran after a button event and I am having issues with being unable to access the global variable arrayTest that is updated with newly pushed value from the filereader onload event.Is there anyway to fix this problem?
Ok. I realized when I woke up that the point where console.log is executed, the async task might still be running which means that the arrayTest is incomplete, so what I this is what I did to fix the issue.
var arrayTest;
var asyncCount;
function handleFiles(files) {
arrayTest = new Array();
asyncCount = 0;
for(var i = 0; files[i]; i++) {
var reader = new FileReader();
asyncCount += 1;
reader.onload = function(e) {
var binary = e.target.result;
var parentSelector = '#output_' + i;
$(parentSelector).html(binary);
arrayTest.push({ 'bin' : binary, 'parentSelector' : parentSelector });
asyncCount -= 1;
if(asyncCount === 0) {
console.log(arrayTest);
console.log(arrayTest.length);
console.log(arrayTest[0]);
// at this point I am able to access all the array members.
}
};
reader.readAsBinaryString(files[i]);
}
}
function buttonClick() {
var files = [file1, file2];
handleFiles(files);
}