So I'm currently trying to make a simple quiz app for Github's Noops Challenge using their Fizzbot API .
I am storing and assembling the URL of the current question and next question in global variables.
var baseurl = "https://api.noopschallenge.com";
var nextQuestion = "/fizzbot/questions/1";
var url = "";
I have a submit function that sends a POST request to the server and receives the URL of the next question if the answer is correct.
function submit() {
var answer = document.getElementById("answer").value;
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var response = JSON.parse(this.responseText);
this.nextQuestion = response.nextQuestion; fizzbot
this.url = baseurl + this.nextQuestion;
console.log("Next Question: " + this.url);
}
};
xhttp.open("POST", this.url, true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.send(answer);
}
In addition to my submit button, I have a next button. After submitting a correct answer, the below function still prints https://api.noopschallenge.com/fizzbot/questions/1 to the log.
function next() {
console.log(this.url);
}
I am pretty sure it has something to do with the asynchronous nature of the POST request, but am not sure what the best way to solve it is. I've posted a more complete snippet for a functioning example of what's happening.
var question = ""; var baseurl = "https://api.noopschallenge.com"; var nextQuestion = "/fizzbot/questions/1"; var url = ""; function load() { this.url = this.baseurl + this.nextQuestion var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var response = JSON.parse(this.responseText); this.question = response.message; document.getElementById("question").innerHTML = this.question; } }; xhttp.open("GET", this.url, true); xhttp.send(); } function submit() { var answer = document.getElementById("answer").value; var responseObject = {answer: answer} var responseJSON = JSON.stringify(responseObject); var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { var response = JSON.parse(this.responseText); this.nextQuestion = response.nextQuestion; this.url = baseurl + this.nextQuestion; document.getElementById("result").innerHTML = response.result; document.getElementById("nextQuestion").innerHTML = response.nextQuestion; console.log("Next Question: " + this.url); } }; xhttp.open("POST", this.url, true); xhttp.setRequestHeader("Content-type", "application/json"); xhttp.send(responseJSON); } function next() { console.log("URL to load: " + this.url); //GET request next question }
<!DOCTYPE html> <html> <head> <title>Noops Challenge | FizzBot Bot</title> <script src="Fizzbot.js" type="text/javascript"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <link rel="stylesheet" href="main.css"> </head> <body onload="load()"> <nav class="navbar navbar-dark bg-dark"> <a class="navbar-brand" href="#"> <img src="https://noopschallenge.com/static/animation/fizzbot/images/img_3.png" width="30" height="30" class="d-inline-block align-top" alt=""> FizzBuzz Quiz </a> <!-- <span class="navbar-brand mb-0 h1">FizzBuzz Quiz</span> --> </nav> <div class="container"> <div class="row" style="margin-top:5%;"> <div class="col-sm-2"></div> <div class="col-sm-8"> <div class="card"> <div class="card-header"> Question <span id="questionNumber">1</span> </div> <div class="card-body"> <h5 id="question" class="card-title">Filler Question</h5><br> Answer: <input type="text" id="answer"> <p class="card-text"><br> Result: <span id="result"></span><br> Next Question: <span id="nextQuestion"></span><br> </p> <button class="btn btn-primary" onclick="submit()" value="">Submit</button> <button class="btn btn-primary" onclick="next()" value="">Next</button> </div> </div> </div> <div class="col-sm-2"></div> </div> </div> <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script> </body> </html>
Global variables are stored in the window
object. this
can refer to window
as well as pretty much any other object. Also, not using this
might get you a global variable as well.
This will run in the global context:
function load() {
this.url = this.baseurl + this.nextQuestion
Here this
=== window
, so this.url
is built from your global variables.
The context changes here:
...
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var response = JSON.parse(this.responseText);
this.question = response.message;
document.getElementById("question").innerHTML = this.question;
}
};
Here, this
refers to the xhttp
object. When setting this.question
, you're creating a new property on xhttp
and using that value to set the <h5 id="question">
text. This works, it just doesn't change your global question
variable.
This again uses the global variable:
xhttp.open("GET", this.url, true);
...
}
Something alike happens when using the submit button:
function submit() {
...
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var response = JSON.parse(this.responseText);
this.nextQuestion = response.nextQuestion;
this.url = baseurl + this.nextQuestion;
Both this.nextQuestion
and this.url
create properties in this (new!) xhttp
object. However, since you didn't put this.
in front of baseurl
, and there's no local variable with that name, the global variable will be used! So, implicitly you're doing this: xhttp.url = window.baseurl + xhttp.nextQuestion
That's why this will show a nice new full URL:
console.log("Next Question: " + this.url);
}
};
But again, the request itself is still done using the initial URL, since we're leaving the xhttp
scope and using the never changed global value here:
xhttp.open("POST", this.url, true);
...
}
... and here:
function next() {
console.log("URL to load: " + this.url);
//GET request next question
}
Long story short: use window.url
to set the global value inside another scope.
It seems like it had more to do with actual variable scope than it had to do with the async aspect of the code. Instead of dealing with a bunch of messy this
references, I just put most of my globals inside of an object which ended up making more sense anyways.
Using an object with getters and setters I am able to access all of my variables throughout the code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.