XHR calls return empty - javascript

I am new to AJAX and I am trying to make a call to my json file but it is not returning anything in console. I looked into network tab, the xhr status is 200.
const xhr = new XMLHttpRequest();
xhr.readyState = function(){
if(xhr.readyState === 4){
console.log(xhr.responseText)
}
}
xhr.open('GET','data/task.json');
xhr.send();
and task.json is
{
"jobs": [
{
"id": 7,
"title": "Clerk",
"employer": {
"name": "AOL"
},
"location": "Floria",
"salary": "$45k+"
}
]
}
I tried parsing it and using console to print it out but the console is empty as well.

There a few things to notice in the request that you are making.
You need to add the status to 200 because it's the OK status. Meaning that your request go through. So that part will exactly become (this.readyState == 4 && this.status == 200).
You also need to change from using triple equal signs === to == because you are not comparing by TYPE as a triple equals is used in JS.
Using the event handler xhttp.onreadystatechange instead of xmr.readySate. Here is a link to the Mozilla documentation.
So it should become:
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange= function(){
if(xhttp.readyState === 4 && xhttp.status == 200){
console.log(xhr.responseText)
}
}
xhr.open('GET','data/task.json');
xhr.send();
Here is a detailed documentation from W3Schools Documentation with example.

You need onreadystatechange not readyState
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
console.log(xhr.responseText)
}
}
xhr.open('GET','data/task.json');
xhr.send();

Instead of xhr.readyState you should use xhr.onreadystatechange
like that:
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
console.log(xhr.responseText)
}
}

Related

How to make callback run asynchronously?

I have a JavaScript function called getAandB which takes a callback. getAandB firstly gets value 'a' using ajax. It then invokes the callback with value 'a' as an argument. The callback gets value 'b' and console.logs both 'a' and 'b' to the console. so I get {"key":"a"} {"key":"b"} in the console.
I thought that the two ajax calls would happen simultaneously / asynchronously. However, they seem to run one after the other ie. synchronously.
The JavaScript code and the PHP code for the ajax requests is shown below:
index.html:
<script>
function getAandB(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
callback(xhr.responseText)
}
}
xhr.send();
}
function callback(resultA){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
const resultB = xhr.responseText;
console.log(resultA, resultB);
}
}
xhr.send();
}
getAandB(callback);
</script>
ajax-a.php:
<?php
sleep(5);
$response = [
"key" => "a",
];
echo json_encode($response);
The code for ajax-b.php is the same as for ajax-a.php except the value of $response.key is b not a.
I thought that the above code would result in ajax calls being made simultaneously to get 'a' and 'b'. However if the PHP code sleeps for 5 seconds for both ajax-a.php and ajax-b.php, then it takes 10 seconds for the console.log to appear. If only one of the ajax-?.php scripts sleeps for 5 seconds then it takes 5 seconds for the console.log to appear.
How can I use callbacks to allow me to combine the results of ajax calls, as I have done here, but to make the individual calls happen simultaneously / asynchronously? Alternatively, is not possible to implement this with callbacks?
If you want the request to ajax-b to me made at approximately the same time as the request for ajax-a then you need to make the respective calls to xhr.send() at approximately the same time.
At the moment, the call to ajax-b's send() takes place as part of callback() which you only call after you have received the response to the request for ajax-a.
You then need to add additional logic to determine when you have received both responses so you log both bits of data at the same time (assuming you still want to do that).
A rough and ready way to do that, keeping to your current approach, would look something like this:
function getA(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
callback(xhr.responseText)
}
}
xhr.send();
}
function getB(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
const resultB = xhr.responseText;
callback(xhr.responseText)
}
}
xhr.send();
}
function getAandB() {
const data = [];
function callback(responseData) {
data.push(responseData);
if (data.length === 2) {
console.log(...data);
}
}
getA(callback);
getB(callback);
}
getAandB();
We have better tools for that these days though, thanks to promises and modern APIs (like fetch) which support them natively.
async function getAandB() {
const dataPromises = [
fetch("./ajax-a.php").then(r => r.text()),
fetch("./ajax-b.php").then(r => r.text())
];
const data = await Promise.all(dataPromises);
console.log(...data);
}
getAandB();
I tried to edit my question but 'the edit queue was full'.
It took me a while to understand #Quentin's answer but I finally realized it relies on the fact that both instantiations of the callback function are altering the same variable (I think that is called by reference and is the default situation with arrays). Given this, although the instantiations know nothing about each other, it is possible to know when both ajax calls have completed by checking to see if the data array has been updated twice. If it has then both must have completed and data can be consoled out.
There is no need for the getAandB function. This much simpler and less confusing code works exactly the same as Quentin's answer:
<script>
const data = [];
function getA(){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
data.push(xhr.responseText);
if (data.length === 2){
console.log(...data);
}
}
}
xhr.send();
}
function getB(){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
data.push(xhr.responseText);
if (data.length === 2){
console.log(...data);
}
}
}
xhr.send();
}
getA();
getB();
</script>

onload equivalent to onreadystatechange (readyState: 4, status: 200)

Is onload equivalent to onreadystatechange with readyState 4, status 200?
This SO post says yes
But if they are equivalent, then why does this MDN article nest the two as such:
var xhr = new XMLHttpRequest();
xhr.open("GET", "/bar/foo.txt", true);
xhr.onload = function (e) {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.error(xhr.statusText);
}
}
};
xhr.onerror = function (e) {
console.error(xhr.statusText);
};
xhr.send(null);
[EDIT] Not duplicate of:
Is onload equal to readyState==4 in XMLHttpRequest?
The second answer in the above post explains that it is not exactly the same as readyState === 4. However, if you include status === 200 you have addressed the difference he/she talks about. My OP shows status nested inside readyState.

Post request body google api

I am trying to create a draft in gmail using google api.
After authorization I am having trouble using POST to send request body. Here is a simplified version of my code.
var token = hash[1].split('=')[1]; // getting token
var body = "some text";
var base64message = Base64.encode(body); //uses base64 library to encode message
var params ={
"message": {
"raw": base64message
}
}
var request = new XMLHttpRequest();
request.onload = function(){
console.log(this.responseText); // parseError
}
request.open('POST','https://www.googleapis.com/gmail/v1/users/me/drafts?access_token='+token,true);
request.send(JSON.stringify(params));
Solved forgot this:
request.setRequestHeader('Content-Type', 'application/json');
Instead of:
request.onload = function(){
console.log(this.responseText); // parseError
}
Use onreadystatechange after which you ask if(this.readyState == 4 && this.status == 200){.
this.readyState == 4 means that the request is finished or processed
this.status == 200 means that it also succeeded.
.onload was added in XMLHttpRequest 2 whereas onreadystatechange has been around since the original spec. .onload is equal only to this.readyState == 4.
So your code will look like this:
var token = hash[1].split('=')[1]; // getting token
var body = "some text";
var base64message = Base64.encode(body); //uses base64 library to encode message
var params ={
"message": {
"raw": base64message
}
};
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
};
request.open('POST','https://www.googleapis.com/gmail/v1/users/me/drafts?access_token='+token,true);
request.send(JSON.stringify(params));

Is xhr always available inside onreadystatechange as a property of the argument? Which one to use?

My goal is to make a couple of XHR onreadystatechange handlers self-contained meaning that I'd like to get the XHR object inside them without using a closure (so I'm able to stack them in any order). Here's the main part of the code:
var xmlhttp;
function receiveOriginal()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
{
...
}
}
...
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = receiveOriginal;
xmlhttp.open("GET", url, true);
xmlhttp.send();
Now, I'd like to make it like
function receiveOriginal()
{
xmlhttpInside = ... // get it any way without using a closure
if (xmlhttpInside.readyState == 4 && xmlhttpInside.status == 200)
{
...
}
}
...
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = receiveOriginal;
xmlhttp.open("GET", url, true);
xmlhttp.send();
I've found out that this actually works (at least in Vivaldi and Chrome):
function receiveOriginal(ev)
{
xmlhttpInside = ev.currentTarget;
// or
xmlhttpInside = ev.srcElement;
// or
xmlhttpInside = ev.target;
// each of these return true: xmlhttp === ev.currentTarget , xmlhttp === ev.srcElement , xmlhttp === ev.target
if (xmlhttpInside.readyState == 4 && xmlhttpInside.status == 200)
{
...
}
}
...
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = receiveOriginal;
xmlhttp.open("GET", url, true);
xmlhttp.send();
But the problem is, I'm looking throught a tutorial after tutorial and all of them, even the W3C reference (this is the final one, right?), all of them say nothing about the argument passed to a onreadystatechange handler. So I have no idea:
how widely is this supported?
which one (ev.currentTarget, ev.srcElement or ev.target) should I use, if any? What's the difference between them?
target, currentTarget, and srcElement are all properties of the native Event object (documentation), which onreadystatechange receives (because it is an event handler). There are many ways to handle this - all of which are perfectly fine. I personally prefer to use this for the onreadystatechange callback:
function receiveOriginal() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText)
}
}

NodeJS XMLHttpRequest response

I'm making and app and I need do get the number of verses of a chapter of the bible.
I'm getting the info from http://www.kingjamesbibleonline.org/
In order to do that I am making an XMLHttpRequest to send to the server from the function getVerses() from the site.
The problem that I am facing is that I'm not getting a .responseText from the XMLHttpRequest. When I use firebug and call that function, in the Network tab > Response tab I get nothing but on Network tab > Preview I get the answer.
Where is this answer coming from and what is the variable that has this value?
My node code is as follows:
let XMLHttpRequest2 = require("xmlhttprequest").XMLHttpRequest;
function getVerses() {
let xmlhttp = new XMLHttpRequest2(); //: new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == xmlhttp.DONE ) {
if(xmlhttp.status == 200){
console.log(xmlhttp.responseText);
}
else if(xmlhttp.status == 400) { }
else { }
}
}
xmlhttp.open("POST", "http://www.kingjamesbibleonline.org/ajax.php", true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send('callFunc=getMaxVerseForChapter&book='+'"Genesis"'+'&chapter='+'"2"');
}
getVerses();
Apparently the server is very strict and it expects the header to be called Content-Type and not Content-type. Some kind of poorly written stuff obviously (in PHP). Also get rid of the double quotes around the values you are sending.
Here you go:
let XMLHttpRequest2 = require("xmlhttprequest").XMLHttpRequest;
function getVerses() {
let xmlhttp = new XMLHttpRequest2(); //: new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == xmlhttp.DONE ) {
if(xmlhttp.status == 200){
console.log(xmlhttp.responseText);
}
else if(xmlhttp.status == 400) { }
else { }
}
}
xmlhttp.open("POST", "http://www.kingjamesbibleonline.org/ajax.php", true);
xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xmlhttp.send('callFunc=getMaxVerseForChapter&book=' + 'Genesis' + '&chapter=' + '2');
}
getVerses();
and since you are hardcoding the values, you don't really need string concatenation:
xmlhttp.send('callFunc=getMaxVerseForChapter&book=Genesis&chapter=2);

Categories

Resources