I've been trying to add data into my array for sometime now and it doesn't work. I have the following code:
function OBJMesh(file)
{
this.modelVertex = [];
this.modelColor = [];
var that = this;
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, true);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState == 4)
{
if(rawFile.status === 200 || rawFile.status === 0)
{
var allText = rawFile.responseText;
var lines = allText.split("\n");
for(var i = 0; i < lines.length; i ++)
{
var lineData = lines[i];
var lineString = lineData.split(" ");
if(lineString[0] === "v")
{
var x = parseFloat(lineString[1]);
var y = parseFloat(lineString[2]);
var z = parseFloat(lineString[3]);
/*
this.modelVertex.push(x);
this.modelVertex.push(y);
this.modelVertex.push(z);
this.modelColor.push(0.0);
this.modelColor.push(0.0);
this.modelColor.push(0.0);
this.modelColor.push(1.0);
*/
that.modelVertex.push(10.0);
//document.getElementById("textSection").innerHTML = "testing";
}
}
}
}
}
rawFile.send();
}
OBJMesh.prototype.getModelVertex = function ()
{
return this.modelVertex;
};
OBJMesh.prototype.getModelColor = function ()
{
return this.modelColor;
};
If I comment out the this.modelVertex.push(10.0); it gets pass the error and prints out "testing". But if I uncomment it, it gets stuck there and won't print anything out. Why is it doing this? how can I solve it so it actually pushes the given data to the this.modelVertex array?
Many Thanks
Edit: I have edited my code after dystroy told me what to do and it do work when I try to print the values in the OBJMesh constructor (shown above), but when I try to do this by creating the object in my main function (shown below) it doesn't print anything.
var cubeModel;
function main()
{
cubeModel = new OBJMesh("file:///Users/Danny/Desktop/3DHTMLGame%202/cube.obj");
document.getElementById("textSection").innerHTML = cubeModel.getModelVertex();
}
this isn't your new instance of OBJMesh in the callback but the XMLHttpRequest.
Start by referencing the desired object just before defining the callback :
var that = this;
rawFile.onreadystatechange = function ()
then use it :
that.modelVertex.push(10.0);
Answer to the question in your edit :
Your constructor contains an asynchronous request. Which means your array isn't available immediately but later.
A solution would be to pass a callback to the constructor :
function OBJMesh(file, doAfterInit) {
this.modelVertex = [];
this.modelColor = [];
var that = this;
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, true);
rawFile.onreadystatechange = function () {
if(rawFile.readyState == 4)
{
if(rawFile.status === 200 || rawFile.status === 0)
{
var allText = rawFile.responseText;
var lines = allText.split("\n");
for(var i = 0; i < lines.length; i ++)
{
var lineData = lines[i];
var lineString = lineData.split(" ");
if(lineString[0] === "v"){
that.modelVertex.push(10.0);
if (doAfterInit) doAfterInit();
}
}
}
}
}
rawFile.send();
}
...
cubeModel = new OBJMesh("file:///Users/Danny/Desktop/3DHTMLGame%202/cube.obj", function() {
document.getElementById("textSection").innerHTML = cubeModel.getModelVertex();
});
But having a class here doesn't look like a smart idea.
Related
Very grateful if someone can help me out with the syntax here- I am hoping to make several XML requests, each time getting a different text file. Here is the general structure of my code. How can I get each file in turn (f0, f1 and f2)?
window.onload = function(){
var f = (function(){
var xhr = [];
for (i = 0; i < 3; i++){
(function (i){
xhr[i] = new XMLHttpRequest();
f0 = "0.txt"
f1 = "1.txt"
f2 = "2.txt"
//??? xhr[i].open("GET", file i, true);
xhr[i].onreadystatechange = function () {
if (xhr[i].readyState == 4 && xhr[i].status == 200) {
//do stuff
}
};
xhr[i].send();
})(i);
}
})();
};
Simply put your filenames in an array.
window.onload = function(){
var f = (function(){
var xhr = [];
var files = ["f0.txt", "f1.txt", "f2.txt"];
for (i = 0; i < 3; i++){
(function (i){
xhr[i] = new XMLHttpRequest();
xhr[i].open("GET", files[i], true);
xhr[i].onreadystatechange = function () {
if (xhr[i].readyState == 4 && xhr[i].status == 200) {
//do stuff
}
};
xhr[i].send();
})(i);
}
})();
};
Something like this should work
// ...
for (i = 0; i < 3; i++){
(function (i){
xhr[i] = new XMLHttpRequest();
xhr[i].open('GET', i.toString() + '.txt'); // <-- this line
xhr[i].onreadystatechange = function () {
if (xhr[i].readyState == 4 && xhr[i].status == 200) {
// ....
I have code like this when I console log the fileContent is gives correct output but when I try to get it as a return it gives error.
I want to use the contents of csv file in other functions.While keeping code clean.
;(function(){
function readTextFile(file)
{
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, true);
var fileContent;
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
var allText = rawFile.responseText;
fileContent =csvJSON(allText);
return fileContent;
}
}
}
rawFile.send(null);
}
function csvJSON(csv){
var lines=csv.split("\n");
var result = [];
var headers=lines[0].split(",");
for(var i=1;i<lines.length;i++){
var obj = {};
var currentline=lines[i].split(",");
for(var j=0;j<headers.length;j++){
obj[headers[j]] = currentline[j];
}
result.push(obj);
}
return result; //JavaScript object
//return JSON.stringify(result); //JSON
}
var mainContent = readTextFile("main.csv");
})();
You should know a little about asynchronous work. When you set handler to readystatechange you just subscribing to that event from XMLHttpRequest, your function will be called when this event is fire. Therefore this function can not return something back to you. Except if you specify another function called callback and in handler after all call it.
Look at this:
function readTextFile(file, callback) {
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, true);
var fileContent;
rawFile.onreadystatechange = function () {
if(rawFile.readyState === 4) {
if(rawFile.status === 200 || rawFile.status == 0) {
var allText = rawFile.responseText;
fileContent =csvJSON(allText);
callback(fileContent);
}
}
}
And when you want request:
readTextFile('main.csv', function(data) {
console.log(data);
}
This is how asynchronous calculation work.
I have a file that looks like this on my server:
0 2
1 8
2 3
3 1
//...
I already know how to get the contents of the file, I do it like this:
var file = 'fileName';
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, true);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
var allText = rawFile.responseText;
}
}
}
rawFile.send(null);
The integer on the left in the file increments for each entry, the integer on the right is random. My program specifies an int n and I want to retrieve the value to the right of the left-hand value that is equal to n. In the example, if program specifies n = 2, I want to get 3. How do I do this?
The more traditional approach of searching line by line
var n = '2', l;
var file = 'fileName';
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, true);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
var allText = rawFile.responseText,
lines = allText.split("\n"),
line;
for (var i=0; i<lines.length; i++) {
if (lines[i].indexOf(n) === 0) {
line = lines[i];
break;
}
}
var numbs = line.split(/\s+/);
l = numbs[1];
}
}
}
rawFile.send(null);
One way would be:
var n = 2;
var right = allText.match(new RegExp('^' + n + ' (\\d+)$', 'm'))[1];
I am trying to write a OBJMesh model reader and I've got the OBJMesh class setted up, but when I try to retrieve the stored data in the array by creating the OBJMesh object and call the get function, it doesn't do it.
Here's the code
OBJMesh.js
function OBJMesh(file)
{
this.modelVertex = [];
this.modelColor = [];
this.init = false;
var rawFile = new XMLHttpRequest();
rawFile.open("GET", file, true);
var objmesh = this;
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState == 4)
{
if(rawFile.status === 200 || rawFile.status === 0)
{
var allText = rawFile.responseText;
var lines = allText.split("\n");
for(var i = 0; i < lines.length; i ++)
{
var lineData = lines[i];
var lineString = lineData.split(" ");
if(lineString[0] === "v")
{
var x = parseFloat(lineString[1]);
var y = parseFloat(lineString[2]);
var z = parseFloat(lineString[3]);
objmesh.modelVertex.push(x);
objmesh.modelVertex.push(y);
objmesh.modelVertex.push(z);
objmesh.modelColor.push(0.0);
objmesh.modelColor.push(0.0);
objmesh.modelColor.push(0.0);
objmesh.modelColor.push(1.0);
//document.getElementById("textSection").innerHTML = objmesh.modelVertex[0];
}
}
}
}
objmesh.init = true;
}
rawFile.send();
}
OBJMesh.prototype.getModelVertex = function ()
{
return this.modelVertex;
};
OBJMesh.prototype.getModelColor = function ()
{
return this.modelColor;
};
OBJMesh.prototype.getInit = function ()
{
return this.init;
};
main.js
var cubeModel;
function main()
{
cubeModel = new OBJMesh("file:///Users/DannyChen/Desktop/3DHTMLGame/cube.obj");
while(cubeModel.getInit() === false)
{
//wait for it
}
var cubeVertex = cubeModel.getModelVertex();
document.getElementById("textSection").innerHTML = cubeVertex[0];
}
it just keeps printing out "undefined". Why's that? and how can I fix it??
but it seems that onreadystatechange is an async-Call so,
this.init = true;
will be set before the function onreadystatechange is called.
May be you could set at the end of the onreadystatechange function
objmesh.init = true;
i hope this helps
I am studying javascript and json but I've some problems: I have a script that works with json but the performances of what I wrote aren't that good. The code works only if I do a debug step by step with firebug or other tools and that makes me think that the execution of the code (or a part of it ... the one that creates the table as you'll see) requires too much time so the browser stops it.
The code is:
var arrayCarte = [];
var arrayEntita = [];
var arraycardbyuser = [];
function displayArrayCards() {
var richiestaEntity = new XMLHttpRequest();
richiestaEntity.onreadystatechange = function() {
if(richiestaEntity.readyState == 4) {
var objectentityjson = {};
objectentityjson = JSON.parse(richiestaEntity.responseText);
arrayEntita = objectentityjson.cards;
}
}
richiestaEntity.open("GET", "danielericerca.json", true);
richiestaEntity.send(null);
for(i = 0; i < arrayEntita.length; i++) {
var vanityurla = arrayEntita[i].vanity_urls[0] + ".json";
var urlrichiesta = "http://m.airpim.com/public/vurl/";
var richiestaCards = new XMLHttpRequest();
richiestaCards.onreadystatechange = function() {
if(richiestaCards.readyState == 4) {
var objectcardjson = {};
objectcardjson = JSON.parse(richiestaCards.responseText);
for(j = 0; j < objectcardjson.cards.length; j++)
arrayCarte[j] = objectcardjson.cards[j].__guid__; //vettore che contiene i guid delle card
arraycardbyuser[i] = arrayCarte;
arrayCarte = [];
}
}
richiestaCards.open("GET", vanityurla, true);
richiestaCards.send(null);
}
var wrapper = document.getElementById('contenitoro');
wrapper.innerHTML = "";
var userTable = document.createElement('table');
for(u = 0; u < arrayEntita.length; u++) {
var userTr = document.createElement('tr');
var userTdcard = document.createElement('td');
var userTdinfo = document.createElement('td');
var br = document.createElement('br');
for(c = 0; c < arraycardbyuser[u].length; c++) {
var cardImg = document.createElement('img');
cardImg.src = "http://www.airpim.com/png/public/card/" + arraycardbyuser[u][c] + "?width=292";
cardImg.id = "immaginecard";
userTdcard.appendChild(br);
userTdcard.appendChild(cardImg);
}
var userdivNome = document.createElement('div');
userdivNome.id = "diverso";
userTdinfo.appendChild(userdivNome);
var userdivVanity = document.createElement('div');
userdivVanity.id = "diverso";
userTdinfo.appendChild(userdivVanity);
var nome = "Nome: ";
var vanityurl = "Vanity Url: ";
userdivNome.innerHTML = nome + arrayEntita[u].__title__;
userdivVanity.innerHTML = vanityurl + arrayEntita[u].vanity_urls[0];
userTr.appendChild(userTdcard);
userTr.appendChild(userTdinfo);
userTable.appendChild(userTr);
}
wrapper.appendChild(userTable);
}
The problem is that the code that should make the table doesn't wait for the complete execution of the code that works with the json files. How can I fix it? I would prefer,if possible, to solve that problem with something easy, without jquery and callbacks (I am a beginner).
You'll have to move som code around to make that work. at first, split it up in some functions, then it is easier to work with. I dont know if it works, but the idea is that first it loads the arrayEntita. When that is done, it fills the other 2 arrays. And when the last array has been filled, it builds the table.
var arrayCarte = [];
var arrayEntita = [];
var arraycardbyuser = [];
function displayArrayCards() {
var richiestaEntity = new XMLHttpRequest();
richiestaEntity.onreadystatechange = function () {
if (richiestaEntity.readyState == 4) {
var objectentityjson = {};
objectentityjson = JSON.parse(richiestaEntity.responseText);
arrayEntita = objectentityjson.cards;
BuildArrayEntita();
}
}
richiestaEntity.open("GET", "danielericerca.json", true);
richiestaEntity.send(null);
}
function BuildArrayEntita() {
for (i = 0; i < arrayEntita.length; i++) {
var vanityurla = arrayEntita[i].vanity_urls[0] + ".json";
var urlrichiesta = "http://m.airpim.com/public/vurl/";
var richiestaCards = new XMLHttpRequest();
richiestaCards.onreadystatechange = function () {
if (richiestaCards.readyState == 4) {
var objectcardjson = {};
objectcardjson = JSON.parse(richiestaCards.responseText);
for (j = 0; j < objectcardjson.cards.length; j++)
arrayCarte[j] = objectcardjson.cards[j].__guid__; //vettore che contiene i guid delle card
arraycardbyuser[i] = arrayCarte;
arrayCarte = [];
//If it is the last call to populate arraycardbyuser, build the table:
if (i + 1 == arrayEntita.length)
BuildTable();
}
}
richiestaCards.open("GET", vanityurla, true);
richiestaCards.send(null);
}
}
function BuildTable() {
var wrapper = document.getElementById('contenitoro');
wrapper.innerHTML = "";
var userTable = document.createElement('table');
for (u = 0; u < arrayEntita.length; u++) {
var userTr = document.createElement('tr');
var userTdcard = document.createElement('td');
var userTdinfo = document.createElement('td');
var br = document.createElement('br');
for (c = 0; c < arraycardbyuser[u].length; c++) {
var cardImg = document.createElement('img');
cardImg.src = "http://www.airpim.com/png/public/card/" + arraycardbyuser[u][c] + "?width=292";
cardImg.id = "immaginecard";
userTdcard.appendChild(br);
userTdcard.appendChild(cardImg);
}
var userdivNome = document.createElement('div');
userdivNome.id = "diverso";
userTdinfo.appendChild(userdivNome);
var userdivVanity = document.createElement('div');
userdivVanity.id = "diverso";
userTdinfo.appendChild(userdivVanity);
var nome = "Nome: ";
var vanityurl = "Vanity Url: ";
userdivNome.innerHTML = nome + arrayEntita[u].__title__;
userdivVanity.innerHTML = vanityurl + arrayEntita[u].vanity_urls[0];
userTr.appendChild(userTdcard);
userTr.appendChild(userTdinfo);
userTable.appendChild(userTr);
}
wrapper.appendChild(userTable);
}
i dont know if this check:
if (i + 1 == arrayEntita.length)
BuildTable();
but else you have to check if alle responseses have returned before executing buildtable();
AJAX requests are asynchronous. They arrive at an unknown period during execution and JavaScript does not wait for the server to reply before proceeding. There is synchronous XHR but it's not for ideal use. You'd lose the whole idea of AJAX if you do so.
What is usually done is to pass in a "callback" - a function that is executed sometime later, depending on when you want it executed. In your case, you want the table to be generated after you receive the data:
function getData(callback){
//AJAX setup
var richiestaEntity = new XMLHttpRequest();
//listen for readystatechange
richiestaEntity.onreadystatechange = function() {
//listen for state 4 and ok status (200)
if (richiestaEntity.readyState === 4 && richiestaEntity.status === 200) {
//execute callback when data is received passing it
//what "this" is in the callback function, as well as
//the returned data
callback.call(this,richiestaEntity.responseText);
}
}
richiestaEntity.open("GET", "danielericerca.json"); //third parameter defaults to true
richiestaEntity.send();
}
function displayArrayCards() {
//this function passed to getData will be executed
//when data arrives
getData(function(returnedData){
//put here what you want to execute when getData receives the data
//"returnedData" variable inside this function is the JSON returned
});
}
As soon as you have made the ajax call, put all of the rest of the code inside the readystatechange function. This way, it will execute everything in order.
Edit: #Dappergoat has explained it better than I can.