Add EXTRA parameter to XMLHttpRequest Handler - javascript

Following is the way I know for adding parameters to request handlers for XMLHttpRequest.
var request = new XMLHttpRequest();
function ABC() {
if (request) {
request.open('GET', url, true);
request.onreadystatechange = function() { handler(param1, param2); };
request.send();
}
}
function handler(param1, param2) {
if (request.readyState == 4) {
if (request.status == 200) {
//do something on success
} else {
alert("Invocation Errors Occured");
}
}
}
That is fine and good. But, kindly look at the following code.
var request = new XMLHttpRequest();
function ABC() {
if (request) {
request.open('GET', url, true);
request.onreadystatechange = handler;
request.send();
}
}
function handler(evtXHR) {
if (request.readyState == 4) {
if (request.status == 200) {
//do something on success
} else {
alert("Invocation Errors Occured");
}
}
}
Here, i'm calling the handler without any parameter, but i'm getting an object of type XMLHttpRequestProgressEvent in the evtXHR parameter of the code.
Now I have two questions.
How am I getting evtXHR parameter when I make a parameter-less call?
How to add a parameter along with evtXHR so that I still get the XMLHttpRequestProgressEvent object?
So, I want something like this:
function handler(evtXHR, myParam) {
if (request.readyState == 4) {
if (request.status == 200) {
//do something on success
} else {
alert("Invocation Errors Occured");
}
}
}

You aren't making a call. the XHR object is. The handler function is being called by the XHR object in response to receiving the event.
Don't try to pass it as an argument. Use a closure instead.
Such:
var myData = 1234;
request.onreadystatechange = handler;
function handler(event) {
alert(myData); // Use myData from the wider scope instead of trying to pass it as an argument
}

Related

Connecting JSON API for parsing

I am looking to parse the following page and extract every instance of a name. http://api.openparliament.ca/politicians/.
I have been following this guide for reference: https://www.taniarascia.com/how-to-connect-to-an-api-with-javascript/ However when it runs, there is nothing returned. What am I doing wrong?
var request = new XMLHttpRequest();
request.open('GET', 'api.openparliament.ca/politicians/?format=json', true);
request.onload = function () {
// Begin accessing JSON data here
var data = JSON.parse(this.response);
if (request.status >= 200 && request.status < 400) {
data.forEach(politicians => {
console.log(politicians.name);
});
} else {
console.log('error');
}
}
request.send();
Welcome Sean to StackOverflow.
Well, first of all you have some issues in your code.
Add the http:// in the URL in this line: request.open('GET', 'http://api.openparliament.ca/politicians/?format=json', true);.
You need to wait for XMLHttpRequest.readyState is DONE. In your code you can check the readyState property in this way:
if (request.readyState === 4) {
// Code goes here...
}
Check if the XMLHttpRequest has returned a 200 status code. You can do in this way:
if (request.status === 200) {
// Code goes here...
}
Then with the previous code you can do:
var data = JSON.parse(this.response);
Where data is an object that it has two properties: objects and pagination where objects is an array of objects and pagination is an object.
Then you can do:
data.objects.forEach(politician => {
console.log(politician.name);
});
Here is the complete demo:
(function() {
var request = new XMLHttpRequest();
request.open('GET', 'http://api.openparliament.ca/politicians/?format=json', true);
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
var data = JSON.parse(this.response);
data.objects.forEach(politician => {
console.log(politician.name);
});
} else {
console.log('error');
}
}
}
request.send();
}());
Hope this helps.

Understanding XHR request object in javascript... (confused)

I'm following a simple book and It says:
function createRequest()
{
try
{
request = new XMLHttpRequest();
}
catch (tryMS)
{
try
{
request = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (otherMS)
{
try
{
request = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (failed)
{
request = null;
}
}
}
return request;
}
function getDetails(itemName)
{
var request = createRequest();
if (request==null)
{ alert("Unable to create request");
return;
}
var url= "getDetails.php?ImageID=" + escape(itemName);
request.open("GET",url,true);
request.onreadystatechange = displayDetails;
request.send(null);
}
function displayDetails()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
detailDiv = document.getElementById("description");
detailDiv.innerHTML = request.responseText;
}
}
}
And all this code above is fine and it's okay to me.. but after few pages it says:
ITS VERY IMPORTANT TO REMOVE VAR KEYWORD BEFORE request VARIABLE so the callback can reference the variable...
but how come in example above it worked? is it coincidence if we call a variable 'request' that it will map with global variable in a createRequest method?
Take a look on image below:
Why is this happening ? in one example var before request variable is used and everything is fine, in another var is avoided so the method in callback might access it.. but how come method in a callback is accessing a request variable in first example...
It's confusing because there are 2 similar examples, with different explanations..
EDIT
P.S it says request has to be a global ? :o
Thanks guys
Cheers
In both examples, implicit global variables are created so they can be shared with the callback.
When the second request variable is created, it creates a local variable inside the getDetails function. So when createRequest() returns the global variable, the local variable becomes a reference to it.
This is rather bad advice and shows a lack of understanding on the writers' part. But it seems to be an old text, since activeX objects are deprecated by now, so maybe globals used to be less frowned upon. The proper way is to either send the responseText or responseXML as a parameter to the callback or send the entire request as the parameter for the callback.
Maybe the writer didn't want to make the request code more complex, but imho, this is not a good way to teach people things.
function createRequest( method, url, callback, payload ) {
var request = new XMLHttpRequest();
if ( !request ) {
alert( "Unable to create request" );
return null;
}
request.open( method, url );
request.onreadystatechange = function() {
if (request.readyState === 4 && request.status === 200 ) {
callback( request.responseText );
}
};
request.send( payload );
};
function getDetails( itemName, callback ) {
createRequest( "GET", "getDetails.php?ImageID=" + escape(itemName), callback, null );
};
function displayDetails( detail ) {
var detailDiv = document.getElementById("description");
detailDiv.innerHTML = detail;
};
getDetails( "someItemName", displayDetails );
you are right, in your first example, function createRequest is not using var, which mean you are creating a global variable request when excute request = new XMLHttpRequest();.
We should avoid using gobal var in most situation.
function createRequest() {
try {
// add var so it's not global variable
var request = new XMLHttpRequest();
} catch (tryMS) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (otherMS) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
request = null;
}
}
}
return request;
}
function getDetails(itemName)
{
var request = createRequest();
if (request==null)
{ alert("Unable to create request");
return;
}
var url= "getDetails.php?ImageID=" + escape(itemName);
request.open("GET",url,true);
// create anonymous function to call your callback and pass `request` as local variable
request.onreadystatechange = function(){
displayDetails(request);
};
request.send(null);
}
function displayDetails(request)
{
if (request.readyState == 4)
{
if (request.status == 200)
{
detailDiv = document.getElementById("description");
detailDiv.innerHTML = request.responseText;
}
}
}

Method in class not being called after XMLHttpRequest is done

I have the following method to log into my API:
login()
{
var formData = new FormData();
formData.append("admin[email]", "user");
formData.append("admin[password]", "pass");
var request = new XMLHttpRequest();
request.open("POST", "my_link");
request.onreadystatechange = (function() {
if (request.readyState === XMLHttpRequest.DONE && request.status === 201)
{
return function() { this.loadMembers(); }
}
});
request.send(formData);
}
Then I have my method that I'm trying to call AFTER my post async request is completely done:
loadMembers()
{
....
}
Now for some reason, this.loadMembers() is never being called. If I put a testing console.log() right above it (not within the return callback) it calls just fine - so I know that the requestState and request status is correct.
Is there a better way to do this? Or what am I doing wrong?
Thanks
It is because you are returning a function instead of just calling loadMembers.
So instead of:
request.onreadystatechange = (function() {
if (request.readyState === XMLHttpRequest.DONE && request.status === 201)
{
return function() { this.loadMembers(); }
}
});
You likely want:
var that = this;
request.onreadystatechange = (function() {
if (request.readyState === XMLHttpRequest.DONE && request.status === 201)
{
that.loadMembers();
}
});
Remember the "this" in login() is not the same this as the one inside the (function() { if....}) so you need to save this var that = this in the way that rasmeister shows.

Does an AJAX request override another?

I have a dynamic AJAX function which has many different modes (I call the function with different parameters and check via switch-case which mode has to be used) but when I call the AJAX function with different parameters directly one after another using the same XMLHttpRequest it seems that the second request overrides the first one.
Is that possible?
Here is a example for my function(EDIT):
$(function() {
ajax("test_1");
ajax("test_2");
});
function ajax(mode)
{
switch (mode)
{
case "test_1":
request = null;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {
}
}
}
if (!request) {
console.log("Kann keine XMLHTTP-Instanz erzeugen");
return false;
} else {
var url = "../ajax.php";
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send('ajax_mode=test&request_mode=test_1');
request.onreadystatechange = function() {
if (request.readyState === 4)
{
interpretRequest_test_1();
}
};
}
break;
case "test_2":
request = null;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {
}
}
}
if (!request) {
console.log("Kann keine XMLHTTP-Instanz erzeugen");
return false;
} else {
var url = "../ajax.php";
request.open('POST', url, true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.send('ajax_mode=test&request_mode=test_2');
request.onreadystatechange = function() {
if (request.readyState === 4)
{
interpretRequest_test_2();
}
};
}
break;
}
}
function interpretRequest_test_1() {
if (request.status != 200) {
console.log("Error");
} else {
alert("1");
}
}
function interpretRequest_test_2() {
if (request.status != 200) {
console.log("Error");
} else {
alert("2");
}
}
Your request variable isn't defined using the var keyword, which makes it a global and thus you are reusing the same XHR object.
If you are reusing the same XMLHttpRequest object then yes, it will abort the previous request if you try to make another request with it, while the other request is in progress.
In your switch statements, define request with the var keyword. This makes the variable scoped to the local scope, and not a global.
switch (mode) {
case "test_1":
var request = null;
...
case "test_2":
var request = null;
...
}
Alternatively do it just once at the top of your function instead of in each case statement.
A more simplified example if you have a global object:
var xhr = new XMLHttpRequest();
function do_smth(){
xhr.open(...);
}
function do_smth2(){
xhr.open(...);
}
do_smth();
do_smth2();
Instead of a global, you need to make the XHR object scoped properly so each call has a unique XHR.
function do_smth(){
var xhr = new XMLHttpRequest();
xhr.open(...);
}
function do_smth2(){
var xhr = new XMLHttpRequest();
xhr.open(...);
}

fallback on XHR fail, outside of the XHR function

I am doing an XMLHttpRequest and I would like to fallback on doing something else (reading a local file) if it fails, but I want to do it outside of the XHR function (getDBfileXHR) itself.
I am using Jquery too.
How is that possible, given the fact that it doesn't seem to work with .done() and .fail(), maybe with a deferred variable or something else ?
getDBfileXHR( encode_utf8("http://john:hispasswd#mysite.com/DBfile.jsonp") );
//here I want to do something else if getDBfileXHR fails like this :
fallbackToLocalDBfile();
function getDBfileXHR(url) {
var request = new XMLHttpRequest();
request.open("GET", url, true); //3rd parameter is sync/async
request.onreadystatechange = function() { //Call a function when the state changes.
if (request.readyState == 4) {
if (request.status == 200 || request.status == 0) {
console.log('we get a response from XHR');
var jsonText = request.responseText.replace("callback(", "");
jsonText = jsonText.replace(");", "");
storeJsonInProdata(JSON.parse(jsonText));
dbReadyDeferred.resolve();
} else {
console.log('error : request.status = '+request.status);
}
}
}
console.log("Sending XMLHttpRequest...");
request.send();
}
function fallbackToLocalDBfile(){
$.get('proDB.jsonp').done(function(data){
console.log(data);
//storeJsonInProdata(data);
//dbReadyDeferred.resolve();
});
}
Mmm something like this maybe :
var d=$.Deferred()
function getDBfileXHR(url) {
....
if (request.readyState == 4) {
...
d.resolve(_MyData);
} else {
console.log('error : request.status = '+request.status);
d.reject(_myError);
}
}
}
console.log("Sending XMLHttpRequest...");
request.send();
}
d.done(function (a){...}).fail(function (b){});

Categories