Ajax request inside another one - javascript

I'm making a website for my battlefield 1 clan, on this website i would like to display every player in this clan and also some of their in-game stats.
The player list is stored in a database and i will get the stats from this api
. This means that i will first get the player list from the database using ajax and then loop through them to get the player stats through a second ajax call in that loop.
It all sounds fun and games till i run my code, sometimes not all of the requests succeed and whenever i'm trying to display a displayname it will always show the one from the last call.
This is my code:
$(document).ready(function() {
$.ajax({
url: 'playerlist.php',
method: 'POST',
data: {
playercheck: 1,
},
success: function(response) {
var len = response.length;
for (var i = 0; i < len; i++) {
var psnid = response[i].psnid;
// second ajax
var request = new XMLHttpRequest();
request.open('GET', 'https://battlefieldtracker.com/bf1/api/Stats/BasicStats?platform=2&displayName=' + psnid);
request.setRequestHeader('TRN-Api-Key', '125a7cbe-1bbe-45d4-9f70-3aa838fc7535');
request.onreadystatechange = function() {
if (this.readyState === 4 && this.status == 200) {
console.log('Status:', this.status);
console.log('Headers:', this.getAllResponseHeaders());
console.log('Body:', this.responseText);
var result = JSON.parse(request.responseText);
console.log(result);
$("#userTable").append(result['profile']['displayName']);
}
};
request.send();
// end second
}
},
dataType: "json"
});
});
If you guys could tell me what is causing this and help me find a solution, that would be great.
Thanks in advance!

This is most likely a variable scope issue. In JavaScript, a variable declaration with var is "hoisted" to the top of the containing function. Also, the scope of the variable is the function, NOT the for loop.
So while it looks as if every for loop iteration ought to be creating a completely separate request, instance, that is not what is happening. And by the time the onreadystatechange event fires, your request value has probably changed.
There are two ways to solve this. First, using the new let or const variable declarations of es6 JS, the scope is different. So if you don't need this to work in older browsers, you can just change from var request to let request, and it should work.
If this isn't possible, you'll need to come up with a way to limit the "scope" of your request variable, such as putting your request code in a function, and then calling the function from inside your for loop.

Try this refactorized version:
$(document).ready(function() {
$.ajax({
url: "playerlist.php",
method: "POST",
data: {
playercheck: 1
},
success: function(response) {
getStats(response);
},
dataType: "json"
});
});
function getStats(stats) {
var len = stats.length;
for (var i = 0; i < len; i++) {
getStatInfo(stats[i].psnid);
}
}
function getStatInfo(psnid) {
var request = new XMLHttpRequest();
request.open(
"GET",
"https://battlefieldtracker.com/bf1/api/Stats/BasicStats?platform=2&displayName=" +
psnid
);
request.setRequestHeader(
"TRN-Api-Key",
"125a7cbe-1bbe-45d4-9f70-3aa838fc7535"
);
request.onreadystatechange = function() {
if (this.readyState === 4 && this.status == 200) {
console.log("Status:", this.status);
console.log("Headers:", this.getAllResponseHeaders());
console.log("Body:", this.responseText);
var result = JSON.parse(request.responseText);
console.log(result);
$("#userTable").append(result["profile"]["displayName"]);
}
};
request.send();
}

Related

Sending json via ajax in wordpress using Vanilla JS

I am sending a json in my server using vanilla JS and it returns a bad request, it seems the server only wants a key value pair like 'page=pageData&action=act', when i do this it works, but i would want to send data that way. Is there a way to make it possible?
When i try to make it in jquery it works fine.
$('.more-headlines').on('click', function() {
var pageData = $(this).data('page');
var pageURL = $(this).data('url');
var act = 'load_more';
var jsondata = {
page : pageData,
action : act
}
var xhr = new XMLHttpRequest();
xhr.open('POST', pageURL, true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onload = function() {
if (xhr.status >=200 && xhr.status < 400) {
var data = JSON.parse(xhr.responseText);
console.log(data);
} else {
console.log('sad');
}
};
xhr.send(JSON.stringify(jsondata));
});
This is my code in jquery
$('.more-headlines').on('click', function () {
var that = $(this);
pageData = $(this).data('page');
newPage = pageData+1;
pageURL = $(this).data('url');
act = 'load_more';
that.addClass('icon-spin');
that.find('span').html('loading headline');
jsondata = {
page : pageData,
action : act
}
$.ajax ({
type: 'POST',
url: pageURL,
data: jsondata,
success: function(response) {
setTimeout( function () {
that.data('page', newPage);
$('#featureOnDemand ul').append(response);
that.removeClass('icon-spin');
that.find('span').html('See more headlines');
}, 500);
}
});
});
I looked at the network tab in chrome and i saw that the send request becomes a key value pair like 'page=pageData&action=act'.
I am stuck in this part because i want to make a vanilla js ajax request in my project. Any idea would be much appreaciated. Many thanks!
You want to serialize your object data. Here's a helper function you can pass your object into:
var serializeObject = function (obj) {
var serialized = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
serialized.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
}
}
return serialized.join('&');
};

Check My Code. Is it a correct way to append?

function saveToDataBase(save_id,textarea_id,question_no,assg_name,testinput,testoutput)
{
document.getElementById(save_id).addEventListener('click',function(){
//alert("Hello");
var question=document.getElementById(textarea_id).value;
var question_id=assignment_name+question_no;
var request;
var url="saveQuesToDataBase.jsp?question="+question+"&question_id="+question_id+"&assg_name="+assg_name;
for(var i=0;i<testinput.length;i++)
{
var v=document.getElementById(testinput[i]).value;
url=url+"&testinput"+i+"="+v;
}
for(var i=0;i<testoutput.length;i++)
{
var v=document.getElementById(testoutput[i]).value;
url=url+"&testoutput"+i+"="+v;
}
var len=testinput.length;
url=url+"&size_of_arr="+len;
if(window.XMLHttpRequest)
{
request=new XMLHttpRequest();
}
else if(window.ActiveXObject)
{
request=new ActiveXObject("Microsoft.XMLHTTP");
}
try
{
request.onreadystatechange=function()
{
if(request.readyState==4 && request.status == 200)
{
alert(request.responseText);
}
};
request.open("GET",url,true);
request.send();
}
catch(e){alert("Unable to connect to server");
}
})
}
The function is called on click, but not redirected to saveQuesToDataBase.jsp . Please see if I could append things to url this way ? Tell me the better way.
testinput and testoutput are the two arrays of id's of textareas.
I used loop to retrieve id and to get the value.
For your code design,I have two suggestions:
a. First I would recommend you using jQuery ajax instead of original Ajax,it will hide the implement of different browsers.With it you can make it like below:
$.ajax({
url:your_request_url,
type:"post",//or get
data:your data,
success:function(data){},
error:function(){}
});
b. since Http Get method has parameter length limit,details can be found at maximum length of HTTP GET request?. You need to use POST instead of GET,while using POST,when can using data to pass more parameters to ajax:
var params ={};//define a parameter object
for(var i=0;i<testoutput.length;i++)
{
var v=document.getElementById(testoutput[i]).value;
params["testoutput"+i]=v;
}
$.ajax({
url:your_request_url,
type:"post",//or get
data:params,//passing the parameters.
success:function(data){},
error:function(){}
});

Get JSON data from external URL and display it in a div as plain text

I have an external resource similar to https://www.googleapis.com/freebase/v1/text/en/bob_dylan which returns a JSON. I want to display the value of result key in a div in html (lets say the name of the div is "summary"). Also the value of result key should be displayed in plain text.
The URL returns the json:
{ "result": "Bob Dylan, born Robert Allen Zimmerman, is an American
singer-songwriter, author, poet, and painter, who has been a major
figure in popular music for five decades. Much of Dylan's most
celebrated work dates from the 1960s, when he became an ......." }
The JSON has just the result key, no other keys
Basically I do not want to use anything other than plain HTML and JavaScript. I am a relative beginner to JavaScript and therefore I ask for commented code.
Here is one without using JQuery with pure JavaScript. I used javascript promises and XMLHttpRequest
You can try it here on this fiddle
HTML
<div id="result" style="color:red"></div>
JavaScript
var getJSON = function(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
resolve(xhr.response);
} else {
reject(status);
}
};
xhr.send();
});
};
getJSON('https://www.googleapis.com/freebase/v1/text/en/bob_dylan').then(function(data) {
alert('Your Json result is: ' + data.result); //you can comment this, i used it to debug
result.innerText = data.result; //display the result in an HTML element
}, function(status) { //error detection....
alert('Something went wrong.');
});
You can do this with JSONP like this:
function insertReply(content) {
document.getElementById('output').innerHTML = content;
}
// create script element
var script = document.createElement('script');
// assing src with callback name
script.src = 'http://url.to.json?callback=insertReply';
// insert script to document and load content
document.body.appendChild(script);
But source must be aware that you want it to call function passed as callback parameter to it.
With google API it would look like this:
function insertReply(content) {
document.getElementById('output').innerHTML = content;
}
// create script element
var script = document.createElement('script');
// assing src with callback name
script.src = 'https://www.googleapis.com/freebase/v1/text/en/bob_dylan?callback=insertReply';
// insert script to document and load content
document.body.appendChild(script);
Check how data looks like when you pass callback to google api:
https://www.googleapis.com/freebase/v1/text/en/bob_dylan?callback=insertReply
Here is quite good explanation of JSONP: http://en.wikipedia.org/wiki/JSONP
Since it's an external resource you'd need to go with JSONP because of the Same origin policy.
To do that you need to add the querystring parameter callback:
$.getJSON("http://myjsonsource?callback=?", function(data) {
// Get the element with id summary and set the inner text to the result.
$('#summary').text(data.result);
});
If you want to use plain javascript, but avoid promises, you can use Rami Sarieddine's solution, but substitute the promise with a callback function like this:
var getJSON = function(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
callback(null, xhr.response);
} else {
callback(status);
}
};
xhr.send();
};
And you would call it like this:
getJSON('https://www.googleapis.com/freebase/v1/text/en/bob_dylan', function(err, data) {
if (err != null) {
alert('Something went wrong: ' + err);
} else {
alert('Your Json result is: ' + data.result);
result.innerText = data.result;
}
});
You can use $.ajax call to get the value and then put it in the div you want to. One thing you must know is you cannot receive JSON Data. You have to use JSONP.
Code would be like this:
function CallURL() {
$.ajax({
url: 'https://www.googleapis.com/freebase/v1/text/en/bob_dylan',
type: "GET",
dataType: "jsonp",
async: false,
success: function(msg) {
JsonpCallback(msg);
},
error: function() {
ErrorFunction();
}
});
}
function JsonpCallback(json) {
document.getElementById('summary').innerHTML = json.result;
}
To display the Json data using Robin Hartman code. You need to add, the below line.
The code he gave gives you Object, object. this code retrieves the data in a better way.
result.innerText =JSON.stringify(data);
Since the desired page will be called from a different domain you need to return jsonp instead of a json.
$.get("http://theSource", {callback : "?" }, "jsonp", function(data) {
$('#summary').text(data.result);
});

Get latest ajax request and abort others

I have been searching and this problem seems simple but cannot find answer. I have multiple request calling different url. But for each url, I only want the result once and it must be the last one in the same url being called. My issue now is "how to get the last one only?" I looked at this and it seems to be 3 years old:
http://plugins.jquery.com/project/ajaxqueue
Any other way to do this nicely and cleanly? If there is something like this, it would be perfect:
queue: "getuserprofile",
cancelExisting: true
(where the existing ajax in getuserprofile queue will be canceled)
Thanks
This explains how to use jQuery to do an ajax call and how to abort it. All you need to do is create an array that stores each request. You could then cancel the previous request while adding the new one.
ajaxRequests = new Array();
queueRequest = function() {
if(ajaxRequests[ajaxRequests.length - 1]) {
ajaxRequests[ajaxRequests.length - 1].abort();
}
ajaxRequests[ajaxRequests.length] = //Insert New jQuery AJAX call here.
}
Since we only want the result of the last request, this is very simple and works.
var ajax = null;
var getFoo = function() {
if(ajax) ajax.abort();
ajax= $.ajax({});
};
getFool();
getFool();
getFool();
getFool();
getFool();
getFool();
only the last request is executed.
Instead of using library, you can use Basic jquery Ajax method :
beforeSend:{}
For example:
xhr = jQuery.ajax({
url: /*Your URL*/
type: "POST",
data: {
//data
},
/* if there is a previous ajax request, then we abort it and then set xhr to null */
beforeSend : function() {
if(xhr != null) {
xhr.abort();
}
},
success:function(){}
});
Yes it's posibble...
In general, I do not recommend stopping requests on the server side, there may be some problems that are hard to detect later.
The idea is to just check the status of a sent request and if necessary, just not send another one.
Here is an example
let activeRequest = false; //global var
let request = null;
$(document).ready(function(){
$('#user').keyup(function(){
let query = $(this).val();
if (query != '') {
const xhr = new XMLHttpRequest();
if (activeRequest === false){
activeRequest = true;
let request = $.ajax({
url: 'https://baconipsum.com/api/?type=all-meat',
method: "POST",
beforeSend: function(){
//Some code here
},
data: {
"type": $(":radio:checked").val(),
"tags": query,
},
success: function (data) {
//Code if succes
console.log('Request with val: ' + query);
},
complete: function() {
activeRequest = false;
}
});
if(!request){
console.log('Req does exist');
}
request.done(function( ) {
activeRequest = false;
console.log('Done, Request Finish');
request = false;
});
}else{
//If ajax still request abort it
console.log('Exiting Request - LastOne Still In que')
//request.abort();
activeRequest = true;
}
} //End iF query != ''
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" name="user" id="user" style="width: 200px;" placeholder="Enter User Name" />
It takes some work to customize it for you but I think it will help guide everyone for you.
//Edit
I forgot, u can customize this code, for example add
let value = $('#output').val();
value.slice(0,-1);
If the request is still pending... Or just another idea, just block the possibility of entering more characters, there are plenty of solutions

Prototype and Ajax.Request scope

I'm having trouble getting the correct scope within prototype's Ajax.Request class. What I'm trying to do is write a simple API which wraps ajax requests:
API = Class.create({
initialize:function(api_token)
{
this.api_token = api_token;
this.request_uri = new Template('/api/#{api_token}/#{resource}.json');
this.status = 0;
this.last_result = null;
},
some_api_call:function()
{
var result = this._request('resource', {'id':1});
// and so on...
},
_request:function(resource, params)
{
var uri = this.request_uri.evaluate({"api_token":this.api_token,"resource":resource});
new Ajax.Request(uri,
{
contentType:'application/json',
method:'get',
parameters:params,
onSuccess:function(r)
{
alert(this);
this.last_result = r.responseJSON;
this.status = r.status;
}
});
return this.last_result;
}
});
When I'm in the onSuccess() method I expected +this+ to refer to the parent object, but it is giving me DOMWindow. I can't seem to get that response data into the API class at all. I figure it is something stupid (binding?), but I just can't seem to think this one out today.
Thanks
Okay. I missed the bigger problem. I was requesting asynchronously so it was setting the result, just not immediately. To be fair, it was also a binding issue. Here is the proper request:
_request:function(resource, params)
{
var uri = this.request_uri.evaluate({"api_token":this.api_token,"resource":resource});
new Ajax.Request(uri,
{
asynchronous: false,
contentType:'application/json',
method:'get',
parameters:params,
onSuccess:function(r)
{
this.last_result = r.responseJSON;
this.status = r.status;
}.bind(this)
});
alert(this.status);
return this.last_result;
}
Your solution should NOT work?
You need to use local variables above the nested function and then convert them into the 'this' scope:
_request:function(resource, params)
{
var uri = this.request_uri.evaluate({"api_token":this.api_token,"resource":resource});
var last_result = "";
var status = "";
new Ajax.Request(uri,
{
asynchronous: false,
contentType:'application/json',
method:'get',
parameters:params,
onSuccess:function(r)
{
last_result = r.responseJSON;
status = r.status;
}
});
this.last_result = last_result;
this.status = status;
alert(this.status);
return this.last_result;
}

Categories