Hey everybody I have a problem.
I am building a website and I want to fetch data from two different xml files with two different functions.
ShowResult is used to get a game score and the name of a specific user.
GiveFeedback also needs the score from the first function to fetch a fitting feedback about this score from a different xml file.
I don´t get an error Message. My only problem is that the second function (giveFeedback) isn´t able to fetch data from the xml because it needs a variable (score) from the first function (showResults). Both functions work on their own but I am unable to “transfer” the score data from showResults to giveFeedback.
How can I transfer the score data to the function GiveFeedback or is there a better way to resolve this problem?
Thanks!
i tried some solutions (global variable, inserting the first function in the second,..) which were already posted but unfortunately i didn´t managed to get it running.
<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
showResult(xhttp.responseXML);
}
};
xhttp.open("GET", "user.xml", true);
xhttp.send();
function showResult(xml) {
var name = "";
var score = "";
path1 = "/userdb/user/name";
path2 = "/userdb/user/score";
var nodes = xml.evaluate(path1, xml, null, XPathResult.ANY_TYPE, null); var result = nodes.iterateNext();
name = result.childNodes[0].nodeValue;
var nodes = xml.evaluate(path2, xml, null, XPathResult.ANY_TYPE, null); var result = nodes.iterateNext();
//Thats wehere the variable (score) is, which i need for the second function (giveFeedback)
score = result.childNodes[0].nodeValue;
document.getElementById("user").innerHTML = "Congratulations " + name + ", you made " + score;
}
var xhttp2 = new XMLHttpRequest();
xhttp2.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
givefeedback(xhttp2.responseXML);
}
};
xhttp2.open("GET", "feedback.xml", true);
xhttp2.send();
function givefeedback(xml) {
var feedback = "";
// This is where it´s needed
if (score > 1){
path = "/feedback/congratulations[percentage=25]/text";
}
else if (score > 8){
path = "/feedback/congratulations[percentage=50]/text";
}
var nod = xml.evaluate(path, xml, null, XPathResult.ANY_TYPE, null);
var res = nod.iterateNext();
feedback = res.childNodes[0].nodeValue;
document.getElementById("feedback").innerHTML = feedback;
}
</script>
i managed to resolve my problem.
first of all i had to declare a global variable outside the functions.
Then i had to convert the fetched variable (score) to a Number.
Related
This question already has answers here:
While looping a jquery ajax call
(3 answers)
Closed 1 year ago.
My code:
<script type="text/javascript">
var x = 1;
var data = JSON.parse( document.getElementById('json').innerHTML);
var next = data['next'];
var jsonData = data['data'];
while (next != null) {
x = x+1;
var nextFileUrl = data['next'];
console.log('next:', nextFileUrl);
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
data = this.response;
next = JSON.parse(this.response)['next'];
console.log('newNext:',next);
newJsonData = JSON.parse(this.response)['data'];
console.log('newJsonData:',newJsonData);
jsonData['data'].push(newJsonData);
}
});
xhr.open("GET", nextFileUrl);
xhr.send(null);
}
</script>
Data example:
{
"next" : "path2",
"data" : "some data here"
}
I have multiple JSON files described as above that I need to access consecutively, in a "while next != null" kind of loop, starting with the data that's already in the page. For every call, I need to get the data value, and do something with it, and then make the next call. Currently, my code seems to constantly be logging the result from the first response only.
I'm fairly new to javascript and ajax, and have no experience with jquery. I can't use fetch, as I need the solution to work for all browsers. I'm looking for the best solution to this between JS, Ajax and JQuery if someone can point me in the right direction.
Your sending async requests in a while loop and expecting a value to update each iteration, but that will never work since the loop will not wait for the request to complete. Rather than a loop, you can call a function recursively until the condition is satisfied
var x = 1;
var data = JSON.parse(document.getElementById('json').innerHTML);
var next = data['next'];
var jsonData = data['data'];
function cycle() {
if (!next) return;
x = x + 1;
var nextFileUrl = next;
console.log('next:', nextFileUrl);
const xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function() {
if (this.readyState === this.DONE) {
data = this.response;
next = JSON.parse(this.response)['next'];
console.log('newNext:', next);
newJsonData = JSON.parse(this.response)['data'];
console.log('newJsonData:', newJsonData);
jsonData['data'].push(newJsonData);
// call the function
if (next) cycle();
}
});
xhr.open("GET", nextFileUrl);
xhr.send(null);
}
Before I start, here is the API. Super simple: https://www.cryptonator.com/api
To note, I have worked with api before, but i used a await async function, but for some reason I couldn't get that to work....but I found a tutorial for doing this with XML http request, so I decided to just move forwards doing it in XML because I was able to make a simple Bitcoin ticker.
I am building a simple widget to display the prices of Bitcoin, Litecoin, and Ethereum using the cryptonator API. Like I said above, I made a bitcoin ticker with the first function ( see code below ), and it works great. However, I am having issues trying to get 3 different currencies.
Here is what I am trying to do.
var url = "https://api.cryptonator.com/api/ticker/btc-usd";
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var json = JSON.parse(this.responseText);
parseJson(json);
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
function parseJson(json) {
var usdValue = json["ticker"]["price"];
document.getElementById("data").innerHTML = usdValue;
var usdValue = usdValue.replace(/[^\d.\-]/g, "");
var usd = parseFloat(usdValue);
document.getElementById("data").innerHTML = "$ " + usd.toFixed(2);
}
//
//
var xmlhttp2 = new XMLHttpRequest();
var url2 = "https://api.cryptonator.com/api/ticker/ltc-usd";
xmlhttp2.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var json = JSON.parse(this.responseText);
parseJson(json);
}
};
xmlhttp2.open("GET", url2, true);
xmlhttp2.send();
function parseJson(json) {
var LTCusdValue = json["ticker"]["price"];
// document.getElementById("data2").innerHTML = LTCusdValue;
var LTCusdValue = LTCusdValue.replace(/[^\d.\-]/g, "");
var LTCusd = parseFloat(LTCusdValue);
document.getElementById("data2").innerHTML = "$ " + LTCusd.toFixed(2);
}
//
//
//
var xmlhttp3 = new XMLHttpRequest();
var url3 = "https://api.cryptonator.com/api/ticker/eth-usd";
xmlhttp3.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var json = JSON.parse(this.responseText);
parseJson(json);
}
};
xmlhttp3.open("GET", url3, true);
xmlhttp3.send();
function parseJson(json) {
var ETHusdValue = json["ticker"]["price"];
// document.getElementById("data3").innerHTML = ETHusdValue;
var ETHusdValue = ETHusdValue.replace(/[^\d.\-]/g, "");
var ETHusd = parseFloat(ETHusdValue);
document.getElementById("data3").innerHTML = "$ " + ETHusd.toFixed(2);
}
As you can see, I am trying to make 3 request to 3 different APis, but it isn't working. If I comment out all but one of these functions, it works fine. My issues comes when i try to use all 3 at once. If i use Bitcoin and Litecoin only, it will actually work, but will just break again once I try to use the 3rd function ( to get ethereum price ).
The parseJson function is defined three times. This means that every time you write the function it will overwrite the previous definition. So in your case only the last parseJson function will be used for all three requests. You could do a couple of things.
Write three different variations. (Bad practice)
Though this would be the less favorable of the options. It will require you to have repeated code copied multiple times. This can be done more efficiently.
function parseJson1(json) {
...
}
function parseJson2(json) {
...
}
function parseJson3(json) {
...
}
Add an argument to the function. (Good practice)
Give the parseJson function a second argument that selects the element to output the value. This should be the id of the element you'll want to select.
This is the better solution because it only requires you to write a function once and call it multiple times accounting for the variations.
function parseJson(json, id) {
var output = document.getElementById(id); // Select the element based on the id.
if (output === null) { // If element is not found, stop the function.
return;
}
var price = json["ticker"]["price"];
var usdValue = price.replace(/[^\d.\-]/g, "");
var usd = parseFloat(usdValue);
output.innerHTML = "$ " + usd.toFixed(2);
}
The last technique is applicable to the rest of your code. Be aware of repeating yourself. You'll write much cleaner and better code when you only have to write something once.
If I understood you well you can create a method for all cryptos and avoid repeting the same code. If you run the example below you will be able to see all cryptos and also it's easy to add new ones:
const URL = 'https://api.cryptonator.com/api/ticker/'
const cryptos = ['btc', 'ltc', 'eth']
cryptos.map(crypto => {
fetch(`${URL}${crypto}-usd`)
.then(data => data.json())
.then(({ ticker: { base, price } }) => console.log(`${base}: ${(+price).toFixed(2)}`))
})
We are using fetch that is modern XHR. Hope this help.
You should be able to write an async wrapper function for this using a Promise.. This will allow you to use async/await with XHR..
To make using XHR a lot easier, you can use the built in fetch API.. According to this, most browsers support fetch.. All in all, I prefer using fetch over axios, XHR, etc.. but since you specifically asked about XHR, that is how I answered.
If you did not want to await each response, you can do something like this:
// basic XHR wrapper function for 'get'
function getXHR(url) {
return new Promise(function(resolve, reject) {
const xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
this.status == 200
? resolve(this.responseText)
: reject(this.status);
}
};
xhr.send();
});
}
const ethElement = document.getElementById("eth");
const bcElement = document.getElementById("bc");
const lcElement = document.getElementById("lc");
// etherium
getXHR("https://api.cryptonator.com/api/ticker/eth-usd")
.then(eth => {
// Can turn into JSON like this:
//const ethJson = JSON.parse(eth);
ethElement.innerHTML = eth;
})
// bitcoin
getXHR("https://api.cryptonator.com/api/ticker/btc-usd")
.then(bc => {
// Can turn into JSON like this:
//const bcJson = JSON.parse(bc);
bcElement.innerHTML = bc;
})
// litecoin
getXHR("https://api.cryptonator.com/api/ticker/ltc-usd")
.then(lc => {
// Can turn into JSON like this:
//const lcJson = JSON.parse(lc);
lcElement.innerHTML = lc;
})
<h1>eth:</h1>
<pre id="eth"></pre>
<h1>bc:</h1>
<pre id="bc"></pre>
<h1>litecoin:</h1>
<pre id="lc"></pre>
I have created the following demo to show you how to accomplish this using async/await:
Init(); // call 'main' function
// basic XHR wrapper function for 'get'
function getXHR(url) {
return new Promise(function(resolve, reject) {
const xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
this.status == 200
? resolve(this.responseText)
: reject(this.status);
}
};
xhr.send();
});
}
// "Main" function
async function Init() {
const ethElement = document.getElementById("eth");
const bcElement = document.getElementById("bc");
const lcElement = document.getElementById("lc");
// etherium
const eth = await getXHR("https://api.cryptonator.com/api/ticker/eth-usd");
const ethJson = JSON.parse(eth);
ethElement.innerHTML = ethJson.ticker.price + " " + ethJson.ticker.target;
// bitcoin
const bc = await getXHR("https://api.cryptonator.com/api/ticker/btc-usd");
const bcJson = JSON.parse(bc);
bcElement.innerHTML = bcJson.ticker.price + " " + bcJson.ticker.target;
// litecoin
const lc = await getXHR("https://api.cryptonator.com/api/ticker/ltc-usd");
const lcJson = JSON.parse(lc);
lcElement.innerHTML = lcJson.ticker.price + " " + lcJson.ticker.target;
}
div h1,
div p {
display: inline;
vertical-align: top;
font-family: 'Open Sans', sans-serif;
line-height: 38px;
}
<div>
<h1>eth:</h1>
<p id="eth"></p>
</div>
<div>
<h1>btc:</h1>
<p id="bc"></p>
</div>
<div>
<h1>ltc:</h1>
<p id="lc"></p>
</div>
I am using the following code to check my database for login information and receive it back inside the application but I am having the issue that I cannot parse the JSON information. I have parsed it into an array and when I run the following code the console returns:
I am wondering how do I take this a step further and read the number for "loggedin" and get the "username" also. I have tried replacing myArr with myArr[0].loggedin or even with myArr[0] but then I get a return of undefined.
Anyone any suggestions?
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('loginForm').addEventListener('submit', function() {
var usernameTest = document.getElementById('username').value;
var passwordTest = document.getElementById('username').value;
//alert("username is: " + usernameTest);
//console.log("password is: " + passwordTest);
//alert("test");
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
alert(this.responseText);
var myArr = JSON.parse(this.responseText);
chrome.extension.getBackgroundPage().console.log(myArr);
}
};
request.open('GET', 'http://localhost/api/login.php?username='+usernameTest+'&password='+passwordTest);
request.send();
});
});
What worked for me after GaetanoM's comment is:
myArr.UAPlugin[0].loggedin or myArr.UAPlugin[0].username
I'm trying to handle a simple XML file with JS (server-side). So far, with every solution I've tried out, the value shows as "undefined".
I've tried a couple of different approaches, yet I still cannot get past loading the XML file itself and successfully displaying it.
When I've tried to parse it with a DOMParser, the node value is "undefined" (see the present code please).
Another approach I've taken before is to treat it as an XML file without changing it to string beforehand - then I get the '.getElementsByTagName('node')[0]; is not a function' error.
function loadXML(postID){
var xmlhttp = new XMLHttpRequest();
var file = 'logs/queue'+postID+'.xml';
xmlhttp.onreadystatechange = function() {
console.log('[DEBUG]Readystate: '+this.readyState+', status: '+this.status);
if (this.readyState == 4 && this.status ==200) {
myFunction(this);
};
function myFunction(xmlfile) {
var xmlDoc=null;
var data = "";
var parser = new DOMParser();
var user;
xmlDoc = parser.parseFromString(String(xmlfile), "text/xml");
var nodes = xmlDoc.getElementsByTagName("node");
for(i=0; i< nodes.length; i++){
tipper = nodes[i].getAttribute("id");
}
console.log(user)
}
};
xmlhttp.open("GET", file, true);
xmlhttp.send();
}
My only expectation is to obtain the node attribute value of the "node" element.
Instead, I keep getting the "undefined" value as a result.
After two days of struggling with this matter, I finally came up with a working solution.
Therefore, in case somebody was having a problem similar to mine, here goes:
First, I've npm-installed libxmljs. From this point, after quickly checking its wiki page, things went almost silky smooth. The modified code can be analyzed below:
function loadXML(postID){
var xmlhttp = new XMLHttpRequest();
var file = 'file.xml';
xmlhttp.onreadystatechange = function() {
console.log('[DEBUG]Readystate: '+this.readyState+', status: '+this.status);
if (this.readyState == 4 && this.status ==200) {
myFunction(this);
};
}
function myFunction(xmlfile) {
var xmlDoc = libxmljs.parseXml(xmlfile.responseText);
var nodes = xmlDoc.root().childNodes();
var node = nodes[0];
var node_id = xmlDoc.get('//user').attr('id').value();
var uname = xmlDoc.get('//name');
var uamount = xmlDoc.get('//u_amount');
var umessage = xmlDoc.get('//u_message');
console.log('[DEBUG] [id=%s] User: %s. Amount: %s. Message: %s.', node_id, uname.text(), uamount.text(), umessage.text() );
}
xmlhttp.open("GET", file, true);
xmlhttp.send();
};
I intend to print the USD value of ETH from
"https://api.coinmarketcap.com/v1/ticker/ethereum/"
using JavaScript. However, when I include the script
<script type="text/javascript">
var xmlhttp = new XMLHttpRequest();
var url = "";
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var json = JSON.parse(this.responseText);
parseJson(json);
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
function parseJson(json) {
var time = "<b>Last Updated : " + json["time"]["updated"] + "</b>";
var usdValue = "$" + json["eth"]["price.usd"]["rate"];
document.getElementById("data").innerHTML =
usdValue
}
</script>
in my HTML file, along with other scripts of other Price APIs, the code above returns nothing. What am I doing wrong? I need help please.
Try Something like this
<body>
<div id="data" />
<script type="text/javascript">
var json = new XMLHttpRequest(); // start a new variable to store the JSON in
json.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) { // if HTTP header 200 - ok
var object = JSON.parse(this.responseText); // set the variable 'object' to whatever we get back, in our case it is an array of 10 different arrays
for(var i=0;i<object.length;i++){ // looping through json
var item = object[i];
if(item["symbol"] === "ETH"){ // finding when symbol is ETH
var usdValue = "$" + item["price_usd"]; // Fetching price_usd value
document.getElementById("data").innerHTML = usdValue;
}
}
}
};
json.open(
"GET", // method
"https://api.coinmarketcap.com/v1/ticker/ethereum/", // url
true // async
); // initialise the request
json.send(); //send request
</script>
</body>
Run the code snippet
According https://api.coinmarketcap.com/v1/ticker/ethereum/, the return value of JSON.parse(this.responseText) will be a json array. So pass json[0] to your parseJson().
The parsed json doesn't have field/property of 'time' or 'eth'. I suggest you use following code to get what you want.
let time = `<b>Last Updated : ${new Date(parseInt(json['last_updated'])).toDateString()}</b>`;
let usdValue = `\$${json['price_usd']}`;