Because I only see the last element of the for loop - javascript

I'm having a problem; I have the following program code:
var xmlhttp = new XMLHttpRequest();
var url = "https://wjko5k6250.execute-api.us-east-2.amazonaws.com/motorcycle";
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var allmot = JSON.parse(this.responseText);
console.log(allmot);
for(var i = 0, len = allmot.Items.length; i < len; i++)
{
id=allmot.Items[i].id
var url1 = "https://wjko5k6250.execute-api.us-east-2.amazonaws.com/motorcycle/"+id;
console.log(url1);
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myArr = JSON.parse(this.responseText);
console.log(myArr);
document.getElementById("img").src = myArr.Item.image;
document.getElementById("brd").innerHTML = myArr.Item.brand;
}
};
xmlhttp.open("GET", url1, true);
xmlhttp.send();
}
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
allmot is as follows:
Items: Array (4)
0: {brand: 'Guzzi', id: '123456', image: 'moto_guzzi.jpg', date: '27/11/2021 '}
1: {brand: 'Bimota', id: '135623', image: 'bimota.jpg', date: '04/12/2021 '}
2: {brand: 'Ducati', id: '123789', image: 'b_desertx.jpg', date: ' 04/12/2021 '}
3: {brand: 'Benelli', id:' 146975 ', image:' benelli.jpg ', date: '27/11/2021'}
url1 returns (according to the for loop):
https://wjko5k6250.execute-api.us-east-2.amazonaws.com/articles/123456
https://wjko5k6250.execute-api.us-east-2.amazonaws.com/articles/135623
https://wjko5k6250.execute-api.us-east-2.amazonaws.com/articles/123789
https://wjko5k6250.execute-api.us-east-2.amazonaws.com/articles/146975
and so far everything seems to be fine.
The problem is in myArr; I noticed that it returns the image and brand of the last element only, so the one that has id equal to 146975.
Therefore there seems to be problems with the for loop.
Can anyone kindly help me? Thank you all.

As first correction I'd not recycle the XHR object from the outer loop in the inner loop.
When you say xmlhttp.onreadystatechange = function() ... in the inner loop, the xmlhttp is already in the readystate, obtained in the outer loop.
So, without further checking what is going on, I'd use two XHR objects (maybe like outerXmlhttp and innerXmlhttp). I'd also recreate the inner XHR for every cycle with:
var innerXmlhttp;
at the top of the outer closure.
Then, inside the cycle do:
innerXmlhttp = new XMLHttpRequest();
This is because of variable hoisting. If you just do this:
var innerXmlhttp = new XMLHttpRequest();
inside the cycle you may get a different behaviour. Just don't do it and write what you mean (hoist variables and assign them where you actually need it).
If all of this isn't enough ask a new, more precise question about what is going on.
This is your code with the corrections:
var outerXmlhttp = new XMLHttpRequest();
var url = "https://wjko5k6250.execute-api.us-east-2.amazonaws.com/motorcycle";
outerXmlhttp.onreadystatechange = function() {
var innerXmlhttp;
if (this.readyState == 4 && this.status == 200) {
var allmot = JSON.parse(this.responseText);
console.log(allmot);
for(var i = 0, len = allmot.Items.length; i < len; i++)
{
id=allmot.Items[i].id
var url1 = "https://wjko5k6250.execute-api.us-east-2.amazonaws.com/motorcycle/"+id;
console.log(url1);
innerXmlhttp = new XMLHttpRequest();
innerXmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myArr = JSON.parse(this.responseText);
console.log(myArr);
document.getElementById("img").src = myArr.Item.image;
document.getElementById("brd").innerHTML = myArr.Item.brand;
}
};
innerXmlhttp.open("GET", url1, true);
innerXmlhttp.send();
}
}
};
outerXmlhttp.open("GET", url, true);
outerXmlhttp.send();
EDIT: #Teemu's eagle eye
As #Teemu points out in his comment, if you reassign values over and over to the same DOM objects like this:
document.getElementById("img").src = myArr.Item.image;
document.getElementById("brd").innerHTML = myArr.Item.brand;
you're clearly overwriting whatever value was there before. Instead, you should create and append those DOM objects, more like this:
var img = document.createElement("img");
img.src = myArr.Item.image;
var brd = document.createElement("p");
brd.innerText = myArr.Item.brand;
document.getElementById("motlist").append(img);
document.getElementById("motlist").append(brd);
Obviously, you'll need a <div id="motlist"></div> element or some other parent in the DOM to which to append the new elements.
For paging you may also want to clear those elements in the list... but here we're going overboard.

Related

How do I convert this code block into a Javascript loop?

This function operates perfectly, onclick it subtracts a price amount from 7 ‘cosT’ divs and 1 ‘cosT1’ div, as if removing an item from a shopping cart.
function changePrice0000() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var x = document.querySelectorAll(".cosT, .cosT1");
x[0].innerHTML = parseFloat(Number(x[0].innerHTML) - Number(x[7].innerHTML)).toFixed(2);
x[1].innerHTML = parseFloat(Number(x[1].innerHTML) - Number(x[7].innerHTML)).toFixed(2);
x[2].innerHTML = parseFloat(Number(x[2].innerHTML) - Number(x[7].innerHTML)).toFixed(2);
x[3].innerHTML = parseFloat(Number(x[3].innerHTML) - Number(x[7].innerHTML)).toFixed(2);
x[4].innerHTML = parseFloat(Number(x[4].innerHTML) - Number(x[7].innerHTML)).toFixed(2);
x[5].innerHTML = parseFloat(Number(x[5].innerHTML) - Number(x[7].innerHTML)).toFixed(2);
x[6].innerHTML = parseFloat(Number(x[6].innerHTML) - Number(x[7].innerHTML)).toFixed(2);
x[7].innerHTML = parseFloat(Number(x[7].innerHTML) - Number(x[7].innerHTML)).toFixed(2);
}
};
xhttp.open("GET", "text/p0000.txt", true);
xhttp.send();
}
I’ve tried a few variations of the following, nooby attempts at looping and getting it to work but without even remote success…
function changePrice0000() {
for(i=0; i<7; i++) {
var xhttp = new XMLHttpRequest();xhttp.onreadystatechange = function() {if (this.readyState == 4 && this.status == 200) {
var x = document.querySelectorAll(".cosT, .cosT1");
x[n].innerHTML = parseFloat(Number(x[n].innerHTML) - Number(x[7].innerHTML)).toFixed(2);
x[0].innerHTML = parseFloat(Number(x[0].innerHTML) - Number(x[7].innerHTML)).toFixed(2);}};
xhttp.open("GET", "text/p0000.txt", true);
xhttp.send();
}
}
…way beyond my capabilities , one for the experts I think, explicit assistance or just a point in the right direction would be most gratefully appreciated.
You were close, you only need the for loop around the part of the code you want to repeat. You also used an undefined variable n instead of the i in the loop, as #Rup mentioned in the comments:
function changePrice0000() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var x = document.querySelectorAll(".cosT, .cosT1");
for(i = 0; i<7; i++) {
x[i].innerHTML = parseFloat(Number(x[i].innerHTML) - Number(x[7].innerHTML)).toFixed(2);
}
xhttp.open("GET", "text/p0000.txt", true);
xhttp.send();
}
}
}
Here a small snippet with a simple loop solution:
var x = document.querySelectorAll(".cost");
x.forEach(function(el) {
el.innerHTML = parseFloat(Number(el.innerHTML) - Number(x[7].innerHTML)).toFixed(2);
});
<div class="cost">1</div>
<div class="cost">2</div>
<div class="cost">3</div>
<div class="cost">4</div>
<div class="cost">5</div>
<div class="cost">6</div>
<div class="cost">7</div>
<div class="cost">8</div>
function changePrice0000() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
var x = document.querySelectorAll(".cosT, .cosT1");
// loop over n starts here
for (n = 0; n < 7; n++) {
x[n].innerHTML = parseFloat(
Number(x[n].innerHTML) - Number(x[7].innerHTML)
).toFixed(2);
}
// loop ends here
}
xhttp.open("GET", "text/p0000.txt", true);
xhttp.send();
};
}
maybe this is what you mean? N is the var, so I from your example will not work, and you gotta makes sure your loop is inside of where you want to handle it...
Ok so huge thank you to the blisteringly fast expert responses, bit of jigging about–here is what is working perfectly (don’t ask me how :), endeavoured to indent a bit:
function changePrice0000() {var xhttp = new XMLHttpRequest();xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var x = document.querySelectorAll(".cosT, .cosT1");
// loop begins
for(n=0; n<7; n++) {
x[n].innerHTML = parseFloat(Number(x[n].innerHTML) - Number(x[7].innerHTML)).toFixed(2)};
// loop ends
x[n].innerHTML = parseFloat(Number(x[n].innerHTML) - Number(x[7].innerHTML)).toFixed(2);}};
xhttp.open("GET", "text/p0000.txt", true);
xhttp.send();}
Thanks again guys !!!
You just have to put for loop to the code which you want to repeat.
var n=7
for(i = 0; i <= n; i++) {
x[i].innerHTML = parseFloat(Number(x[i].innerHTML)-(Number(x[n].innerHTML)).toFixed(2);
}

How do I get certain a property value from multiple objects using json?

I'm using this site:
https://jsonplaceholder.typicode.com/users/
as ajax practice with javascript.
I'm trying to get a certain property value from multiple IDs.
Let's use phone for example.
How can I loop through all the files and get every id and his phone?
Like this:
id : 1
phone : 123
id : 2
phone : 124
I'm trying to use for...in but I can't really get the hang of it rather than looping through only 1 of them.
function callToServer(param) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
//if (this.readyState == (4) Done && this.status == (200) All good) {
if (this.readyState == 4 && this.status == 200) {
res = JSON.parse(this.responseText);
for (var key in res) {
demo.innerHTML += `${key} : ${res[key]}<br>`;
}
}
}
// notice that I used "9" after to loop only through 1 :)
xhttp.open("GET", "https://jsonplaceholder.typicode.com/users/9", true);
xhttp.send();
}
Loop over the array and get the id and phone properties of each element. You can use forEach() for this rather than a for loop. See Why is using "for...in" for array iteration a bad idea?
function callToServer() {
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
let html = '';
let res = JSON.parse(this.responseText);
res.forEach(user => demo.innerHTML +=
html += `id ${user.id}: phone ${user.phone}<br>`;
)
demo.innerHTML = html;
}
}
xhttp.open("GET", "https://jsonplaceholder.typicode.com/users", true);
xhttp.send();
}
Access your data using res[key].id
function callToServer(param) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
res = JSON.parse(this.responseText);
for (var key in res) {
demo.innerHTML += `${key} : ${res[key].id}<br>`;
}
}
}

How to split the content of xmlhttp.response in javascript

i did manage to build a code that works and it does the splitting when added manually:
var input = '10;11;15;16';
var arr = input.split(';');
// update the content of the div with ID "humid"
document.getElementById('humid').textContent = arr[0];
document.getElementById('humid').style.width = `${arr[0]}%`;
document.getElementById('temp').textContent = arr[1];
document.getElementById('temp').style.width = `${arr[1]}%`;
document.getElementById('uv').textContent = arr[2];
document.getElementById('uv').style.width = `${arr[2]}%`;
document.getElementById('info').textContent = arr[3];
document.getElementById('info').style.width = `${arr[3]}%`;
the problem i have is that i want to use the data from this XMLHttpRequest,
this is how i get my value:
function readForestall() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("ForestAll").innerHTML =
this.responseText;
}
};
xhttp.open("GET", "readFORESTALL", false);
xhttp.send();
}
setInterval(function() {
readForestall();
}, 5000);
i did try a lot of things with no result, like this:
var input = 'ForestAll';
or input = document.getElementById('ForestAll').value
regards

Find all duplicate lines and display non matches

Is there an easy way to do this in javascript?
arr = ["red","blue","green","red","blue", "yellow"]
output = ["green", "yellow"]
Basically if a value is shown only once in an array output it. The order is random.
There are easy ways to do this in php, javascript is confusing me.
Need to run this on at least 4000 values, not sure what's faster, regex or array functions?
Thanks for any help.
code having problem with: myarrs values aren't accessible outside the function, I am stuck there. The file loads otherwise,
var txt = '';
var myarr = '';
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
if(xmlhttp.status == 0 && xmlhttp.readyState == 4){
txt = xmlhttp.responseText;
myarr = txt.split("\n");
});
//alert(myarr.length);
xmlhttp.open("GET","list.csv",true);
xmlhttp.send();
var map = new Object();
for(var i = 0; i < myarr.length; i++)
{
if(map[myarr[i]] === undefined)
{map[myarr[i]] = 1; }
else
{map[myarr[i]]++; }
}
var result = new Array();
for(var i = 0; i < myarr.length; i++)
{
if(map[myarr[i]] > 1)
{ //do nothing
}
else
{result.push(myarr[i]);}
}
console.debug(result);
document.write(result);
If order of the unique elements doesn't matter, you can store the item in an object and increment the count, like this
var arr = ["red", "blue", "green", "red", "blue", "yellow"], obj = {};
arr.forEach(function(currentItem) {
obj[currentItem] = (obj[currentItem] || 0) + 1;
});
And then filter out all the items for which the value is not 1, to get the unique values
var unique = Object.keys(obj).filter(function(currentItem) {
return obj[currentItem] === 1;
});
console.log(unique);
# [ 'green', 'yellow' ]
Note: If you don't declare the variables with var keyword, they will become global properties.
var txt = '';
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
//for local files use status zero not 200
if(xmlhttp.status == 0 && xmlhttp.readyState == 4){
txt = xmlhttp.responseText;
myarr = txt.split("\n");
display = myarr.filter(function(a,b,c){return c.indexOf(a)===c.lastIndexOf(a);});
document.write(display);
// myarr.replace(",", "<br>");
}
};
xmlhttp.open("GET","list.csv",true);
xmlhttp.send();
The only thing I don't understand is why does the page keep trying to load after it finishes processing the whole file.

Loading an array of XML files with asynchronous XMLHttpRequest

I want to load an array of XML files, and store them in an array.
Code example:
var src = [ "a", "b", "c", "d" ];
var dest = {};
for (var i in src) {
var req = new XMLHttpRequest();
req.open("GET", src[i], true);
req.onreadystatechange = function(aEvt) {
if (req.readyState == 4) {
if (req.status == 200) {
dump(i + "\n");
dest[i] = req.responseXML;
}
}
}
req.send(null);
}
However, the dump result is always
3
3
3
3
It shows that the i referenced in callback is always the outer i, so the XML files cannot be stored correctly.
So, how to solve this issue? We have about 50 XML files to load and loading them one by one is not acceptable.
Thank you.
Don't use for..in to loop over arrays. Use a normal for loop.
You make the typical mistake of creating a function in a loop. JavaScript has no block scope, only function scope, so i will always refer to the last element of the array you looped over when the functions you created are executed. They all have a reference to the same i. You can solve this by using an immediately executing function that returns a function (thus, capturing the value of i).
If you do this, you also have to capture a reference to req, otherwise it will always refer to the last generated XMLHttpRequest (the same reason as for i).
So one solution would be:
var src = [ "a", "b", "c", "d" ];
var dest = {};
for (var i = src.length;i--;) {
var req = new XMLHttpRequest();
req.open("GET", xmlfile, true);
req.onreadystatechange = (function(i, req) {
return function(aEvt) {
if (req.readyState == 4) {
if (req.status == 200) {
dump(i + "\n");
dest[i] = req.responseXML;
}
}
};
}(i, req)); // capturing the current value/reference of i and req
req.send(null);
}
#Spiny Norman's solutions might be more readable ;)
You could do something like this:
var src = [ "a", "b", "c", "d" ];
var dest = {};
var loadXml = function(i) {
var req = new XMLHttpRequest();
req.open("GET", xmlfile, true);
req.onreadystatechange = function(aEvt) {
if (req.readyState == 4) {
if (req.status == 200) {
dump(i + "\n");
dest[i] = req.responseXML;
}
}
}
req.send(null);
};
for (var x = 0; x < src.length; x++) {
loadXml(x);
}
By the way, it seems you're always loading the same xmlfile, but I'm sure this is different in your actual code ;)

Categories

Resources