Comparaison between different input files in javascript, cannot reach global variable - javascript

I'm trying to open different JSON files and compare each others values.
To do it, I used this to read the files. But I'm trying to save every data in a global variable 'data'. I think it's a asynchronous mistake but I'm pretty new to javascript and I didn't understand where the error come from.
Here is my code :
var data = {}
function readmultifiles(files) {
var reader = new FileReader();
function readFile(index) {
if( index >= files.length ) return;
var file = files[index];
reader.onload = function(e) {
// get file content
var bin = e.target.result;
bin = JSON.parse(bin);
for(task in bin['values']){
addData(bin['info']['date'],task,bin['values'][task]);
}
// do sth with bin
readFile(index+1);
}
reader.readAsBinaryString(file);
}
readFile(0);
console.log("readmultifiles");
console.log(data);
return data;
}
function addData(date, task, value){
if(data[task] == undefined){
data[task] = {};
}
data[task][date] = value;
}
var fileInput = document.querySelector('#file');
fileInput.addEventListener('change', function() {
console.log(fileInput);
var files = fileInput.files;
readmultifiles(files);
console.log("index");
console.log(data);
console.log(data['task_1']); // I can't display this object because 'undefinned'
});
What happens? When I'm trying to watch 'data', firefox console display me the object but I cannot watch inside the object.
Firefox display
What do I need to do to make a good solution. Should I use timers to wait?

Related

How to work with the url of a fileReader object?

Hello! I'am trying to make it work a function called loadDocument, who need a url of the loaded files from the user local computer to work. I'm writing an API to load document from local user computer, and show it on a web reader.
This is my upload button :
<input type="file" id="input" onchange="module.onLoadSelection();" alt="Browse" name="upload"/>
This is my function without fileReader :
var onLoadSelection = function () {
var select = document.getElementById('input');
if (select && select.value) {
var id= '';
var url = select.files.item(0).name;
module.loadDocument(url,id);
}
};
This is my function with fileReader :
var loadTest = function (input) {
var file = document.querySelector('input[type=file]').files[0];
console.log("file loaded! ->", file); // i can read the obj of my file
var reader = new FileReader();
var id = ''; // don't need rightnow
var url = reader.readAsDataURL(file);
console.log("url :", url); // show me undefined....
module.loadDocument(url,id);
}
What i am trying is to get the url of the loaded file from user computer to get my function loadDocument working. She need a url parameter to work.
loadDocument is an API function, i assume i can't get the filepath of my user due to security reason.
What do i need to change/update on my loadDocument(); function to work?
Edit : In fact, nothing to change. The correct way to read my file was :
<input type="file" id="input" onchange="module.onLoadSelection(this.files);" alt="Browse" name="upload"/>
var onLoadSelection = function (files) {
if (files && files.length == 1) {
var id = '';
var url = URL.createObjectURL(files[0]);
module.loadDocument(url,id);
}
};
Don't use a FileReader at all.
When you want to display a File (or a Blob) that is in the browser's memory or on user's disk, then all you need is to generate an URL that do point to this memory slot.
That's exactly what URL.createObjectURL(blob) does: it returns a Blob URI (blob://) that points to the data either in memory or on the disk, acting exactly as a simple pointer.
This method has various advantages over the FileReader.readAsDataURL() method. To name a few:
Store the data in memory only once, when FileReader would need it at reading, then generate a copy as an base64 encoded, and an other one at displaying...
Synchronous. Since all it does is to generate a pointer, no need to make it async.
Cleaner code.
const module = {
loadDocument: (url) => {
document.body.append(
Object.assign(
document.createElement('iframe'),
{ src: url }
)
)
}
};
document.querySelector('input[type=file]').addEventListener('input', function (evt) {
var file = this.files[0];
var url = URL.createObjectURL(file);
module.loadDocument(url);
});
<input type="file">
function PreviewFiles(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
//alert(e.target.result);
$('#pclogo').prop('src', e.target.result)
.width(200)
.height(200);
var base64result = e.target.result.split(',')[1];
$('input[name="logo"]').val(base64result);
};
reader.readAsDataURL(input.files[0]);
}
}
File objects have a readAsDataURL method.
Use that.
var file = document.querySelector('input[type=file]').files[0];
var reader = new FileReader();
reader.addEventListener("load", function () {
doSomethingWithAUrl(reader.result);
}, false);
if (file) {
reader.readAsDataURL(file);
}

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

joining an array nested in an object inside of an array using .join() not working

I am taking in a file, parsing it, storing the info in an object and pushing that object to an array.One of the values of the object is a 'sequence': [] name value pair. Once I store a DNA sequence into the value of 'sequence' in my object I want to join all of the elements. However, I have tried doing this using .join() to no avail. Below is my code:
// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {
// Great success! All the File APIs are supported.
} else {
alert('The File APIs are not fully supported in this browser.');
}
var objArray = [];
var obj;
function parse(event) {
//Get the file from HTML input tag
var file = event.target.files[0];
if(file) {
//Create a new file reader
var reader = new FileReader();
//When the file reader loads
reader.onload = function(evt) {
//Add the contents of file to variable contents
var contentsByLine = evt.target.result.split('\n');
//Alert user the file upload has succeeded
console.log('File ' + file.name + ' was successfully loaded.');
for(var i in contentsByLine){
if(contentsByLine[i][0] == '>'){
obj = {
id: contentsByLine[i],
sequence: [],
lead_trim: 0,
trail_trim: 0
};
objArray.push(obj);
}else{
obj.sequence.push(contentsByLine[i]);
}
// console.log(objArray[i]['sequence']);
}
console.log(objArray)
// Create the DataView.
var dataView = new Slick.Data.DataView();
// Pass it as a data provider to SlickGrid.
var grid = new Slick.Grid("#table", dataView, columns, options);
// Make the grid respond to DataView change events.
dataView.onRowCountChanged.subscribe(function (e, args) {
grid.updateRowCount();
grid.render();
});
dataView.onRowsChanged.subscribe(function (e, args) {
grid.invalidateRows(args.rows);
grid.render();
});
var data = [];
for (var i in objArray){
objArray[i]['sequence'].join();
data.push(objArray[i]);
}
dataView.setItems(data);
dataView.getItems();
//console.log(data);
}
reader.readAsText(file);
} else {
alert('Failed to upload file!');
}
}
document.getElementById('fileItem').addEventListener('change', parse, false);
You are using join incorrectly. Join returns a value. You need to set it to something.
for (var i in objArray){
objArray[i]['sequence'].join();
data.push(objArray[i]);
}
Should instead be:
for (var i = 0; i < objArray.length; i++){
objArray[i]['sequenceString'] = objArray[i]['sequence'].join();
data.push(objArray[i]);
}
You need to store result in variable eg:
var result = objArray[i]['sequence'].join();
data.push(result);
shorter:
data.push( objArray[i]['sequence'].join() );

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.

HTML5 FileReader in Opera

I am trying to read multiple local ogg audio files using the file reader api in opera 12 by converting them into data urls and storing them into an array which I intend to access later.
function music(list)
{
var playlistlength=0;
try
{
for (var temp=0; temp < list.files.length; temp++)
{
f[playlistlength][0] = list.files.item(temp).name;
var freader = new FileReader();
freader.onload = function(frevent){
f[playlistlength][1]=frevent.target.result;
};
freader.readAsDataURL(list.files[temp]);
playlistlength++;
}
}
catch(e)
{
alert("Error");
}
}
However upon inspection in the debugger, in the for loop , no statement is executed and it jumps to the catch block, unable to figure it out.Can someone explain why its happening and any alternatives if possible? Thanks in advance.
This works on jsFiddle. I made it from your code, is your use of it similar ?
HTML :
​<input type="file" id="browser"/>​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
Javascript :
function music(list)
{
var playlistlength=0;
var f = new Array();
try
{
for (var temp=0; temp < list.files.length; temp++)
{
var music = new Array();
music[0] = list.files.item(temp).name;
var freader = new FileReader();
freader.onload = function(frevent){
music[1]=this.result;
f.push(music);
alert(f);
};
freader.readAsDataURL(list.files[temp]);
playlistlength++;
}
alert(f);
}
catch(e)
{
alert(e);
}
}
function FileSelectHandler(e) {
var list = e.target || e.originalEvent.dataTransfer;
music(list);
}
document.getElementById("browser").onchange = FileSelectHandler;
Why it didn't work ?
First you tried to set a value in f[playlistlength][1], because of
the onload function asynchronously executing after the
playlistlength++. It crashed because this reference didn't exist.
f was probably wrong declared ​

Categories