event listener 'change' is not engaging? - javascript

I'm trying to read in a file, split the words out into an array, count the length of each word, then reassign each word into a new array if the word is greater than a number entered. When the file is selected, thats when the function should execute, perform the above logic and display the result to an element. The EventListener doesn't seem to be getting triggered when I set a breakpoint in Chrome. Any suggestions?
I've included the JS and html for troubleshooting. Thanks in advance!
function filteredWords() {
var fileInput = document.getElementById('fileInput'); //create a variable for the html input
var displayResult = document.getElementById('displayResult'); //create a variable for the html display
var temp = document.getElementById('num').value;
var num = parseInt(temp, 10);
fileInput.addEventListener('change', function (e) {
var file = fileInput.files[0]; //store the first file into a variable
var textType = /text.*/; //create a variable for checking if file type is text
if (file.type.match(textType)) { //if the file is of type text
var reader = new FileReader(); //create a new file reader object
var text = "";
var wordArray = [];
var filteredArray = [];
reader.readAsText(file); // read the file
reader.onload = function (e) { //for the onload event
text = reader.result; //assign result to new variable
wordArray = text.split(' '); //split the text words into an array
for (i = 0; i < wordArray.length; i++) { //loop through the array and replace largest word with largest in array
if (wordArray[i].length > num) {
filteredArray += wordArray[i];
}
}
displayResult.innerHTML = "Your filtered words are: "; //display the result in the browser element
for (i = 0; i < filteredArray.length; i++) {
displayResult.innerHTML = largestWord + ", ";
}
};
} else { //display a message if file wasn't read
displayResult.innerHTML = "File not supported!";
}
});
}
//inputs
<input class="" type="number" id="num" />
<input type="file" onclick="filteredWords()" id="fileInput" />
//display
<p id="displayResult" class="control-label"></p>

Related

JQuery: how can I push a file to another input array value?

I have 2 inputs:
each time, I select some files form temp and I want push to another input files.
I do this step:
chage first iput:
<input type="file" id="temp" name="temp[]" onchange="readFile(this);" multiple />
function readFile(input) {
counter = input.files.length;
for(x = 0; x<counter; x++){
if (input.files && input.files[x]) {
const reader = new FileReader();
reader.onload = function (e) {
// add thumbnail picture
}
reader.readAsDataURL(input.files[x]);
}
}
}
I add this code to main js fuction:
var new_file = [];
new_file["id"] = "1";
new_file["main"] = "0";
new_file["delete"] = "0";
new_file["file"] = input.files[x];
files = $("input[name='files[]']").val();
if(!Array.isArray(files)) files = [];
files.push(new_file);
$("input[name='files[]']").val(input[x]);
So finall code:
function readFile(input) {
counter = input.files.length;
for(x = 0; x<counter; x++){
if (input.files && input.files[x]) {
const reader = new FileReader();
var new_file = [];
new_file["id"] = "1";
new_file["main"] = "0";
new_file["delete"] = "0";
new_file["file"] = input.files[x];
files = $("input[name='files[]']").val();
if(!Array.isArray(files)) files = [];
files.push(new_file);
$("input[name='files[]']").val(input[x]);
reader.onload = function (e) {
// add thumbnail picture
}
reader.readAsDataURL(input.files[x]);
}
}
}
So I have 2 problem:
in server side, I got this:
"files" => array:1 [▼
0 => null
]
but temp is ok:
"temp" => array:1 [▼
0 => UploadedFile {#1349 ▶}
]
Also, in line new_file["file"] = input.files[x];, input.files[x] is not a file. it is an object. how can insert file to new_file["file"]?
You can't move the value of one file input to another, it is a security risk.
From copying the value of a form's file input field to another form's input field
If the end result you want to achieve is to have identical values for both the file inputs when user select files for input[name="temp[]"], consider using clone and replace instead:
$('input[name="temp[]"]').change(function() {
var $clone = $this.clone()
$clone.attr('name', 'files[]');
$('input[name="files[]"]').replaceWith($clone);
});

How to work with FileList (from <input type="file">) in Javascript?

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

FileReader output saved to Array

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

recursively build a tree from an array javascript

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

HTML5 File API: onload too slow

I new to JavaScript an jQuery and Google doesn't lead to an answer. I am writing a online Ebook reader. This is the code for a library where the user can input multiple epub files and relevant information(like Author) should be displayed in a table. To do this I need to extract the ePub file. The jsZip library works perfect. The contents must be displayed in a table which is dynamically created(since I don't know the amount of files).
The problem is that the for loops is to fast and creates all the cells with only the name and filesize within them and after the for loop completes the onload of the FileReader executes and adds all the contents into the very last cell. In this code the alert("A") happens as many times as files that were inputted before alert("B") happens. Is there some way that I can make the loops wait until the onload of the FileReader is done?
function handleFileSelect(evt) {
var files = evt.target.files;
var rows = Math.ceil(files.length/3);
var a = 0;
var root = document.getElementById('mainTable');
var tab=document.createElement('table');
tab.style.textAlign = "center";
var row, cell;
var tbo=document.createElement('tbody');
for(var i = 0; i != rows; i++)
{
row=document.createElement('tr');
for(var j = 0; (j < 3);j++)
{
cell = document.createElement('td');
cell.height = "300px";
cell.width = "300px"
if(a <indexes.length)
{
var f = files[a];
var str = f.name;
str = str.substring(0, str.length - 5);
str = "File Name: " + str;
cell.appendChild(document.createTextNode(str));
cell.appendChild(document.createElement('br'));
str = "File Size: " + Math.round(f.size/1024) + " KB";
cell.appendChild(document.createTextNode(str));
cell.appendChild(document.createElement('br'));
var reader = new FileReader();
reader.onload = (function(theFile)
{
return function(e)
{
alert("B");
var zip = new JSZip(e.target.result);
$.each(zip.files, function (index, zipEntry)
{
cell.appendChild(document.createTextNode(zipEntry.name));
cell.appendChild(document.createElement('br'));
//row.appendChild(cell);
});
}
})(f);
reader.readAsArrayBuffer(f);
alert("A");
a++;
}
row.appendChild(cell);
}
tbo.appendChild(row);
}
tab.appendChild(tbo);
root.appendChild(tab);
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
Your problem is that the variable cell used within your onload handler will refer to the last value assigned to cell in the outer loop. You can get around this by putting the file processing in a separate function which will create it's own scope.
function read_zip_file(f, cell) {
var reader = new FileReader();
reader.onload = (function(theFile)
{
return function(e)
{
alert("B");
var zip = new JSZip(e.target.result);
$.each(zip.files, function (index, zipEntry)
{
cell.appendChild(document.createTextNode(zipEntry.name));
cell.appendChild(document.createElement('br'));
//row.appendChild(cell);
});
}
})(f);
reader.readAsArrayBuffer(f);
}
Then within the outer loop you can call:
read_zip_file(f, cell);

Categories