multiple XMLHttpRequest display issue - javascript

I was successfully able to make multiple XMLHttpRequest and this is my code:
var index = ["status", "net"]
for (var i = 0; i < index.length; i++) {
var url = "http://localhost:3000/api/" + index[i];
let http = new XMLHttpRequest();
http.open("GET", url);
http.onreadystatechange = function () {
if (http.readyState === XMLHttpRequest.DONE && http.status == 200) {
console.log(http.responseText);
var respond = JSON.parse(http.responseText);
console.log("respond is" + respond.name);
console.log("respond is" + respond.dhcp_on);
console.log("respond is" + respond.sn);
document.getElementById('device-name').value = respond.name;
}
}
http.send();
}
I am getting the proper value in the console but as I am trying to display the value in my input element with id (device-name) I get undefined.
FYI this is how my console log is looking like
{"name":"DEV 1","sn":"123456789","uptime":123}
respond isDEV 1
respond isundefined
respond is123456789
{"dhcp_on":true,"ip":"1.2.3.4","mask":"1.2.3.4","gw":"1.2.3.4","dns":"1.2.3.4"}
respond isundefined
respond istrue
respond isundefined
Could anyone explain why?
Thanks.

The problem is that you're writing to the same element repeatedly in a loop. The response to your first request has name:
{"name":"DEV 1","sn":"123456789","uptime":123}
but the response to your second response does not:
{"dhcp_on":true,"ip":"1.2.3.4","mask":"1.2.3.4","gw":"1.2.3.4","dns":"1.2.3.4"}
Since the loop does
document.getElementById('device-name').value = respond.name;
both times, you're overwriting the result of the first (which has the name) with the result of the second (which doesn't), exactly like this:
const results = [
{"name":"DEV 1","sn":"123456789","uptime":123},
{"dhcp_on":true,"ip":"1.2.3.4","mask":"1.2.3.4","gw":"1.2.3.4","dns":"1.2.3.4"}
];
// (Using your loop structure and variable names)
for (var i = 0; i < results.length; ++i) {
var respond = results[i];
document.getElementById("device-name").value = respond.name;
}
<input type="text" id="device-name">
You only want to set device-name when processing the first response, not the second. You can do that by checking i, or by checking whether name is in the response:
const results = [
{"name":"DEV 1","sn":"123456789","uptime":123},
{"dhcp_on":true,"ip":"1.2.3.4","mask":"1.2.3.4","gw":"1.2.3.4","dns":"1.2.3.4"}
];
// (Using your loop structure and variable names)
for (var i = 0; i < results.length; ++i) {
var respond = results[i];
if ("name" in respond) {
document.getElementById("device-name").value = respond.name;
}
}
<input type="text" id="device-name">
In this case, if ("name" in respond) { could be if (respond.hasOwnProperty("name")) { or if (respond.name !== undefined) {, whatever you prefer. in checks the whole prototype chain, but the chain is quite short when the object came from JSON.parse.

so by simply adding an if condition to check if the id i want to display is in my returned object or not as #T.J. Crowder explained it worked perfectly
var index = ["status", "net"];
for (var i = 0; i < index.length; i++) {
var url = "http://localhost:3000/api/" + index[i];
let http = new XMLHttpRequest();
http.open("GET", url);
http.onreadystatechange = function () {
if (http.readyState === XMLHttpRequest.DONE && http.status == 200) {
console.log(http.responseText);
var respond = JSON.parse(http.responseText);
if ("name" in respond) {
document.getElementById('device-name').value = respond.name;
}}
}
http.send();
}

Related

Can't pass variable with JSON objects to for loop [duplicate]

This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 6 years ago.
I try to write script to loop through object and return those which type is equal to custom data type set in HTML. Yet im unable to pass variable with array of objects to my for loop. Can you please tell me what am I doing wrong in this code? I receive:
Cannot read property 'length' of undefined
PS. It has to be done in raw JavaScript, no jQuery
var btn = document.getElementById("btn");
var przepisy;
function findData(data) {
var kuchnia = data.dataset.type;
var myRequest = new XMLHttpRequest();
myRequest.onreadystatechange = function() {
if (this.readyState === 4 && this.status == 200) {
przepisy = JSON.parse(myRequest.responseText);
}
};
myRequest.open('GET', 'js/przepisy.json');
myRequest.send();
for (i = 0; i < przepisy.length; i++) {
var results = "";
var obj = przepisy[i];
var type = przepisy.type;
if (type === kuchnia) {
results += obj.name;
document.write(results);
}
}
}
The issue is that you are making the call to your for loop before you get the data back, which is why the length is 0. You should just move the for loop into your response:
function findData(data) {
var kuchnia = data.dataset.type;
var myRequest = new XMLHttpRequest();
myRequest.onreadystatechange = function() {
if (this.readyState === 4 && this.status == 200) {
przepisy = JSON.parse(myRequest.responseText);
for(i = 0; i < Object.keys(przepisy).length; i++) {
var results = "";
var obj = przepisy[i];
var type = przepisy.type;
if(type === kuchnia) {
results += obj.name;
document.write(results);
}
}
}
};
myRequest.open('GET','js/przepisy.json');
myRequest.send();
}

Using Multple Asyncronous Xmlhttprequests to Create/Update Microsoft Dynamics CRM Order Detail Records Not Working

I am trying to send multiple asyncronous xmlhttprequest's using the oData endpoint. Some of them are creating Order details and are updating Order details in Microsoft Dynamics CRM 2013.
If I use the developer tools and manually trace through the code it works fine. However, if I run it from my web resource I constantly get 500 responses from the server. Some of the requests complete correctly, while the others fail.
I am looking for a purely javascript solution. I have tried Googling it and looking at multiple posts on stackoverflow but to no avail. I have used Fiddler2 but the response text is 'Generic SQL Error'. If I run the request again in the composer, it works just fine. Could it be a db locking issue?
Thanks in advance and I can provide more info if need be.
Here is my code with the for-loop:
var updateDetails = function (data) {
var table = document.getElementById("selectedItemTable");
var tbody = table.getElementsByTagName("tbody")[0];
var upsaleQty, qty;
var salesOrderDetailId;
for (var i = 0; i < tbody.childElementCount; i++) {
var prodName = tbody.rows[i].cells[0].innerHTML;
var match = false;
for (var j = 0; j < data.length; j++) {
if (prodName === data[j].product_order_details.tf_ShortName) {
match = true;
upsaleQty = data[j].tf_UpsaleQty ? parseFloat(data[j].tf_UpsaleQty) : 0;
qty = parseFloat(data[j].Quantity) + parseFloat(tbody.rows[i].cells[1].innerHTML);
salesOrderDetailId = data[j].SalesOrderDetailId;
}
}
if (!match) {
var productQuery = odataBaseUrl + "/ProductSet?$filter=tf_ShortName eq '" + prodName + "'&$select=Name,tf_ShortName,ProductId,DefaultUoMId";
performRequest(productQuery, createDetail);
} else {
upsaleQty = upsaleQty + parseFloat(tbody.rows[i].cells[1].innerHTML);
// Update Order Detail
var updateObj = {};
updateObj.tf_UpsaleQty = upsaleQty.toFixed(5);
updateObj.Quantity = qty.toFixed(5);
var updateDetail = JSON.stringify(updateObj);
console.dir("Update " + prodName + ":" + updateDetail);
createUpdateDetail(true, salesOrderDetailId, updateDetail);
}
}
makePdf();
document.getElementById("save").style.visibility = "hidden";
}
Here is the code that sends the create/update request:
var createUpdateDetail = function (update, orderDetailGuid, json) {
var odataReq = odataBaseUrl + "/SalesOrderDetailSet";
if (update) {
odataReq += "(guid'" + orderDetailGuid + "')";
}
var oReq = getXMLHttpRequest();
if (oReq != null) {
oReq.open("POST", encodeURI(odataReq), true);
oReq.setRequestHeader("Accept", "application/json");
oReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
if (update) {
oReq.setRequestHeader("X-HTTP-Method", "MERGE");
}
oReq.send(json);
} else {
alert('Error in creating request.');
}
}
Here is the perform request function:
var performRequest = function (odataUrl, onReadyFunction, concatResults) {
console.dir(odataUrl);
var oReq = getXMLHttpRequest();
if (oReq != null) {
oReq.open("GET", encodeURI(odataUrl), true);
oReq.setRequestHeader("Accept", "application/json");
oReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
oReq.onreadystatechange = function () {
if (oReq.readyState == 4 && oReq.status == 200) {
// Parse the result
if (!concatResults) {
concatResults = new Object();
concatResults.results = new Array();
}
oReq.onreadystatechange = null; //avoids memory leaks
console.dir(oReq.responseText);
var result = window.JSON.parse(oReq.responseText).d;
for (var i = 0; i < result.results.length; i++) {
concatResults.results.push(result.results[i])
}
if (result.__next != null)
performRequest(decodeURI(result.__next), onReadyFunction, concatResults);
else
onReadyFunction(concatResults.results);
}
};
oReq.send();
} else {
alert('Error in creating request.');
}
}
Create Detail function:
var createDetail = function (data) {
// Create Order Detail
var table = document.getElementById("selectedItemTable");
var tbody = table.getElementsByTagName("tbody")[0];
var qty = 0;
for (var i = 0; i < tbody.childElementCount; i++) {
if (data[0].tf_ShortName === tbody.rows[i].cells[0].innerHTML) {
qty = parseFloat(tbody.rows[i].cells[1].innerHTML).toFixed(5);
}
}
var createObj = {};
createObj.SalesOrderId = { Id: orderGuid, LogicalName: "salesorder" };
createObj.ProductId = { Id: data[0].ProductId, LogicalName: "product" };
createObj.Quantity = qty;
createObj.tf_UpsaleQty = qty;
createObj.UoMId = { Id: data[0].DefaultUoMId.Id, LogicalName: data[0].DefaultUoMId.LogicalName };
var createDet = JSON.stringify(createObj);
console.dir("Create:" + createDet);
createUpdateDetail(false, "", createDet);
}
I think ExecuteMultipleRequest to SOAP endpoint it's your solution. As a result you get only one service call instead making multiple service call which is currently implemented in your solution.
In case you avoid generating request string to soap endpoint in your code I would like to recommend you this JS library.
I ended up creating an array and treated it like a queue. I put all of the odata requests to create and update the Order Details in the array and then processed them sequentially. The onreadystatechange would trigger the next request. Granted, it's not as efficient as running the processed in parallel, but it worked for my needs and resolved the 500 errors. Thanks for your help.

How to fetch image through json using jquery or JS in HTML

Can any body help, m totally new in Json I want to fetch the image but m bit confuse in the array and object thing. Or is it possible to fetch image without img tag. Thank you in advance
This is my JSON link
this what I have tried:
function myFunction(worldpopulation) {
var out = "";
var i;
for(i = 0; i<worldpopulation.length; i++)
out += '' + worldpopulation[i].rank;
document.getElementById("id01").innerHTML = out;
}
just help me to fetch "rank" only
{ "worldpopulation":
[
{
"rank":1,"country":"China",
"population":"1,354,040,000",
"flag":"http://www.androidbegin.com/tutorial/flag/china.png"
},
{
"rank":2,"country":"India",
"population":"1,210,193,422",
"flag":"http://www.androidbegin.com/tutorial/flag/india.png"
},
{
"rank":3,"country":"United States",
"population":"315,761,000",
"flag":"http://www.androidbegin.com/tutorial/flag/unitedstates.png"
},
]
}
The first thing you will get the content of your json content from this page using XMLHttpRequest
var request = new XMLHttpRequest();
var url = "http://www.androidbegin.com/tutorial/jsonparsetutorial.txt";
request.onreadystatechange = function() {
if(request.readyState == && request.status == 200) {
var myArr = JSON.parse(xmlhttp.responseText);
myFunction(myArr);
}
}
the implementation of myFunction
function myFunction(myArr)
{
for(var i=0; i< myArr.length; ++i) {
var img ; // get your element you want to place img inside
img.src = myArr[0].flag;
}
}
you can use .filter() to get image array.
var imageArr = [];
imageArr = worldpopulation.filter(function(val,indx){
return val.flag;
});
you can use jquery in following way
$.getJSON( "http://www.androidbegin.com/tutorial/jsonparsetutorial.txt",function( data ) {
$.each( data.worldpopulation, function( key, country) {
console.log('Image Url',country.flag)
});
});

Variable from for loop always returns 0

I am reasonably new to node.js / sails.js and have run into a problem that I know the answer is simple but I cannot seem to work it out.
My code is as follows
SendCompleted : function(req,res)
{
var updated = 0;
var params = req.params.all();
var dt = JSON.parse(decodeURI(params.id));
var connection = new sql.Connection(testrmis, function (err)
{
if (err) {
}
for(var i = 0; i < dt.length; i++) {
var obj = dt[i];
var request = new sql.Request(connection);
request.stream = true;
request.input('branchid', sql.Int(), obj.branch_id);
request.input('picklistid', sql.Int(), obj.picklist_id);
request.input('scanned',sql.Int(),obj.scanned);
request.input('expected', sql.Int(),obj.expected);
request.input('poscode', sql.VarChar(),obj.poscode);
request.input('label', sql.VarChar(), obj.label);
request.input('dt', sql.VarChar(), obj.dt);
request.execute('WAREHOUSE_InsertPiPackData');
request.on('done', function(returnValue) {
updated = updated + returnValue;
console.log(updated);
});
}
res.send("[{\"ReturnValue\":" + updated + "}]");
});
}
I am sending in 4 lines of results and my console.log(updated) counts up as it should for each line, e.g 1,2,3,4
However the res.send result for updated is always 0.
Could anyone please explain why this is happening? My var updated is outside of my loop and this is getting updated correctly, however when the loop is finished it seems to get reset to 0?
returnValue == ##rowcount from the stored procedure
request is async so
res.send("[{\"ReturnValue\":" + updated + "}]");
gets executed even before you get the callback on request as JS doesn't wait for the callback and executes the next line. What you can do is use a counter and place your res.send inside for loop.
SendCompleted : function(req,res)
{
var updated = 0;
var params = req.params.all();
var dt = JSON.parse(decodeURI(params.id));
var connection = new sql.Connection(testrmis, function (err)
{
if (err) {
}
var count = dt.length;
for(var i = 0; i < dt.length; i++) {
var obj = dt[i];
var request = new sql.Request(connection);
request.stream = true;
request.input('branchid', sql.Int(), obj.branch_id);
request.input('picklistid', sql.Int(), obj.picklist_id);
request.input('scanned',sql.Int(),obj.scanned);
request.input('expected', sql.Int(),obj.expected);
request.input('poscode', sql.VarChar(),obj.poscode);
request.input('label', sql.VarChar(), obj.label);
request.input('dt', sql.VarChar(), obj.dt);
request.execute('WAREHOUSE_InsertPiPackData');
request.on('done', function(returnValue) {
count--;
updated = updated + returnValue;
console.log(updated);
if(count == 0) res.send("[{\"ReturnValue\":" + updated + "}]");
});
}
});
}
Try for this:
May be Async problem:
for(var i = 0; i < dt.length; i++) {
//Your logic
if(i=== dt.length){
res.send("[{\"ReturnValue\":" + updated + "}]");
}
}
This is because at the time you do request.send, the value of updated is not incremented. This is because request.execute is asynchronous and done handler will be invoked after the res.send has been executed.
I would recommend a promise library (example, q). You can combine the promises and then use Q.all to do req.send when all the promises are done.
See more details here

Chrome Extension - XHR URLs from an array

I have saved some subject URL keys to localStorage and now want to cycle through them a get content of each of them.
// Walk through saved subjects
allSubjects = JSON.parse(localStorage.getItem('subjects'));
var i = 0;
var ii = 0;
var xhrIn = [];
for (i = 0; i < allSubjects.length; i++) {
xhrIn[i] = new XMLHttpRequest();
xhrIn[i].open("GET", "https://myserver.com/" + allSubjects[i], true);
xhrIn[i].onreadystatechange = function() {
if (xhrIn[ii].readyState == 4) {
console.log(xhrIn[ii].responseText);
percents = Math.floor((((ii+1)/allSubjects.length)*100));
$("div#status").text('Downloading... ' + percents + '%');
// Final phase
if ((ii+1) == allSubjects.length) {
$("div#status").text("All downloaded and saved in console.");
}
ii++;
}
};
xhrIn[i].send();
}
}
This is not working, it catches only the first URL, after that my Console log says, that all other URLs were contacted, but xhrIn[i].onreadystatechange closure has never been executed.
It looks like a little bit magical for me... Can anyone explain me this behavior?
Yes, I agree with epascarello, there are some fundamental problems with this code. There is not guarantee that the callbacks assigned to run in the order you are intending. If you want them to run in order, try something like this:
var urls = ['test.php', 'test2.php', test3.php'];// and so on
function myRequest(){
if(urls.length > 0){
var nextUrl = urls.pop(); //TAKE THE NEXT URL (pop() removed from the end)
var xhrIn = new XMLHttpRequest();
xhrIn.open("GET", "https://myserver.com/" + nextUrl, true);
xhrIn.onreadystatechange = function() {
if (xhrIn.readyState == 4) {
console.log(xhrIn.responseText);
//THE FOLLOWING LINE WILL OBVIOUSLY NOT WORK ANY MORE
//percents = Math.floor((((ii+1)/urls.length)*100));
//$("div#status").text('Downloading... ' + percents + '%');
myRequest(); //RECUR WHEN DONE WITH PREVIOUS REQUEST
}
}
}
}
Haven't tested, but should be something like this:
for (i = 0; i < allSubjects.length; i++) {
xhrIn[i] = new XMLHttpRequest();
xhrIn[i].open("GET", "https://myserver.com/" + allSubjects[i], true);
xhrIn[i].onreadystatechange = (function(ii) {
return function() {
if (xhrIn[ii].readyState == 4) {
console.log(xhrIn[ii].responseText);
}
};
})(i);
xhrIn[i].send();
}
Your current percent calculation will jump all over the place as callback functions could be called in random order. You probably would need to rethink that part (create some global counter).

Categories