I'm looking for a way to initialize a var after an ajax call. The problem is that the ajax call is in an another file.
Here is my code :
file1.js
$(document).ready(function () {
getKanbans();
});
function getKanbans() {
var kanbans = RequestSender.getKanbans();
console.log(kanbans); // print undefined
}
RequestSender.js
class RequestSender {
static getKanbans() {
$.ajax({
url: './ajax/select_kanbans.php',
type: 'GET',
success: RequestSender.initKanbanList
});
}
static initKanbanList(data) {
var result = JSON.parse(data);
var kanbans = [];
for (var i = 0; i < result.kanbans.length; ++i) {
var currentKanban = result.kanbans[i];
kanbans.push(new Kanban(currentKanban['Name'], currentKanban['Status']))
}
console.log(kanbans); // correctly displayed
return kanbans;
}
}
I just use jQuery, all my files are included. I think that the problem come from the fact that ajax is async but I don't know how to fix that.
in your example ajax call started but kanbans still undefined
function getKanbans() {
//ajax call started but kanbans still undefined
var kanbans = RequestSender.getKanbans();
console.log(kanbans); // print undefined
}
so you should complete execution after ajax call finished you can do that with the help of promises
for more information Check this
function getKanbans(url) {
var promiseObj = new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log("xhr done successfully");
var response = xhr.responseText;
var responseJson = initKanbanList(response);
resolve(responseJson);
} else {
reject(xhr.status);
console.log("xhr failed");
}
} else {
console.log("xhr processing going on");
}
}
console.log("request sent succesfully");
});
return promiseObj;
}
function initKanbanList(data) {
var result = JSON.parse(data);
var kanbans = [];
for (var i = 0; i < result.kanbans.length; ++i) {
var currentKanban = result.kanbans[i];
kanbans.push(new Kanban(currentKanban['Name'], currentKanban['Status']))
}
console.log(kanbans); // correctly displayed
return kanbans;
}
$(document).ready(function () {
// to call it
getKanbans('./ajax/select_kanbans.php').then(function (kanbans) {
console.log(kanbans);
}, function (error) {
console.log(error);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
This is called modules in javascript. You can implement them using link tags directly. But you are much better served by libraries like RequireJS and others. Then you can do things like:
require(['./RequestSender'], function (RequestSender) {
var rs = new RequestSender();
... //whatever
});
Here is a good SO question that explains modules well: How do I include a JavaScript file in another JavaScript file?
Related
I've got a function that needs to call a link (JSON format), the fact is that I would like to be able to preload this link to smooth and reduce the operation time when calling the function.
onSelectionChanged: function (selectedItems) {
selectedItems.selectedRowsData.forEach(function(data) {
if(data) {
colorMe(data.target)
}
});
}
function colorMe(item){
globalItem = item;
request('http://blablabla/?format=json',findMaterial);
};
function findMaterial(data){
jq310.each(data, function(table) {
if (data[table].identifier == globalItem){
globalData = data[table]
request('http://another-blablabla/?format=json',findMatchArea);
};
});
};
function findMatchArea(areas){
jq310.each(areas, function(area) {
blablabla
The request function that I built just look if the link as been already called, so it's reloading it if true. And also send data from the link to the called function.
If you'r looking to load a static json file you should concider loading it on the top of your file. To do so you should store the datas in a global variable like that :
let datas;
request('http://blablabla/?format=json', (data) => {
datas = data
});
onSelectionChanged: function (selectedItems) {
selectedItems.selectedRowsData.forEach(function(data) {
if(data) {
globalItem = data.target;
findMaterial();
}
});
}
function colorMe(item){
globalItem = item;
};
function findMaterial(){
const data = datas;
jq310.each(data, function(table) {
if (data[table].identifier == globalItem){
globalData = data[table]
request('http://another-blablabla/?format=json',findMatchArea);
};
});
};
I finally found a way to do it properly, here it is :
var mylink = 'https://fr.wikipedia.org/wiki/JavaScript';
function preloadURL(link){
var xhReq = new XMLHttpRequest();
xhReq.open("GET", link, false);
xhReq.send(null);
var jsonObject = JSON.parse(xhReq.responseText);
return jsonObject;
};
jsonObjectInv = preloadURL(mylink);
And I just point to my json variable to parse it (really faster)
function colorMe(item){
globalItem = item;
findMaterial(jsonObjectInv);
};
Problem solved
I have a function to fetch data from a web api and load it in the UI.
I am using angular js with xmlhttprequest to fetch data.
My function is like below.
var testMethod = (resolve,reject)=>{
$scope.responseData = [];
var startCount =0;
var isDataAvaialble = true;
do {
var url = "ur/api/search?start=" +startCount;
$http({
method : 'GET',
url:url,
}).then function successCallback(response){
$scope.data= response.Data;
for (var i =0 ; i<$scope.data.length; i++)
{
// do something
if(condition)
{
$scope.resonseData.push($scope.data[i]);
isDataAvailable = true;
}
else
{
isDataAvailable =false;
break;
}
}
});
startCount ++;
}while(isDataAvailable)
resolve($scope.response);
};
But since I am using Promise inside the loop the loop is getting executed before the promise.
Instead if I use synchronous xmlhttprequest loop is working.
ie instead of
var url = "ur/api/search?start=" +startCount;
$http({
method : 'GET',
url:url,
}).then function successCallback(response){
if I use
var xhr = new XMLHttpRequest();
xhr.open("GET", url, false);
xhr.send(null);
$scope.data = JSON.parse(xhr.responseText);
everything works. But I don't need to use synchronous here.
I need to get this done asynchronously. I need to get the $scope.responseData in other function
Try something like this:
$scope.responseData = [];
function testMethod(startCount = 0) {
const url = `url/api/search?start=${startCount}`;
return $http({ method : 'GET', url })
.then((response) => {
const data = response.Data;
for (let i = 0; i < data.length; i++) {
if(!condition) { return; }
$scope.responseData.push(data[i]);
}
return testMethod(startCount + 1);
});
}
testMethod();
(My solution below)
I have several HTML elements with class .canvas-background of which information is stored in the database. I want to get the information of each element and process it via JavaScript. But somehow I can't pass the response of the AJAX request to another function. Here is what I've tried:
function initTabs() {
var tabs = loadTabInformation();
console.log(tabs); // (1)
// do something else
}
function loadTabInformation() {
var requests = new Array();
var tabs = new Object();
var counter = 0;
$(".canvas-background").each(function () {
var tabNumber = $(this).data("tab-number");
var request = $.ajax({
type: 'POST',
url: '../db/GetTabInformation.ashx',
data: String(tabNumber),
dataType: 'json',
contentType: 'text/plain; charset-utf-8'
})
.done(function (response) {
tabs[counter++] = response;
}).fail(function (jqXHR, textStatus, errorThrown) {
console.log("request error in loadTabInformation()");
console.log(textStatus);
console.log(errorThrown);
});
requests.push(request);
});
$.when.apply($, requests).done(function () {
console.log(tabs); // (2)
return tabs;
});
}
At (1) I get undefined, but at (2) everything seems to be alright.
THE SOLUTION:
Thanks to the answer and the link in the comment #Kim Hoang provided I got this working. The clue seemed to put the done() function in the calling function, that is initTabs() in my case. Another thing I got wrong was to try to do the logic that should be executed after the AJAX requests had finished outside the done callback function. They must be inside (makes sense, if you think about it). And a lot of conosle output helped, to see what function returns what kind of object.
function initTabs() {
var tabInfoRequest = loadTabInfo();
tabInfoRequest[0].done(function() {
var results = (tabInfoRequest[1].length > 1) ? $.map(arguments, function(a) { return a[0]; }) : [arguments[0]];
for (var i = 0; i < results.length; i++) {
// do something with results[i]
}
});
}
function loadTabInfo() {
var tabNumbers = new Array();
$(".canvas-background").each(function () {
tabNumbers.push($(this).data("tab-number"));
});
var requests = $.map(tabNumbers, function (current) {
return $.ajax({
type: 'POST',
url: '../db/GetTabInformation.ashx',
data: String(current),
dataType: 'json',
contentType: 'text/plain; charset-utf-8'
});
});
var resultObject = new Object();
resultObject[0] = $.when.apply($, requests);
resultObject[1] = requests;
return resultObject;
}
Note: I only did the resultObject-thing because I needed the array requests in the initTabs() function.
Thank you very much for helping me!
You do not return anything in loadTabInformation, so of course you will get undefined. You should do it like this:
function loadTabInformation() {
...
return $.when.apply($, requests);
}
function initTabs() {
loadTabInformation().done(function (tabs) {
console.log(tabs); // (1)
// do something else
});
}
var Client = require('node-rest-client').Client;
var client = new Client();
module.exports = {
getWeatherStatus: function() {
var messageData = "";
client.get("http://api.openweathermap.org/data/2.5/weather?q=Pune&appid=123234234234243242", function (data, response) {
console.log(JSON.parse(data));
messageData=data;
});
//how to set the response of that rest call to this messageData object
return messageData;
}
}
this method getWeatherStatus should return the rest response in json format.
Open for totally different suggestion to implement this kind of scenario.
My basic requirement is to use this REST call response and send to other functions.
In getWeatherStatus you use async function client.get. You need wait result from async function and only than return messageData. For this you can use deasync. Example:
var Client = require('node-rest-client').Client;
var client = new Client();
module.exports = {
getWeatherStatus: function() {
var messageData = "";
client.get("http://api.openweathermap.org/data/2.5/weather?q=Pune&appid=123234234234243242", function (data, response) {
console.log(JSON.parse(data));
messageData=data;
});
//We waiting for data.
while (messageData === "") {
require('deasync').sleep(10);
}
return messageData;
}
}
But, maybe, you should return Promise, not data.
Since get is callback function so you have to put your return messageData
in stead of messageData=data.
Code should be like
var Client = require('node-rest-client').Client;
var client = new Client();
module.exports = {
getWeatherStatus: function() {
var messageData = "";
client.get("http://api.openweathermap.org/data/2.5/weather?q=Pune&appid=123234234234243242", function (data, response) {
return JSON.parse(data);
});
}
}
I think you are facing difficulties to deal with with callbacks,
In the method getWeatherStatus, instead of returning the result, you should pass it to a callback function once the treatment is done.
If really you are required to return, galk.in answer seems to be a possible way.
Otherwise, check this out,
var Client = require('node-rest-client').Client;
var client = new Client();
module.exports = {
getWeatherStatus: function(then) {
var messageData = "";
client.get("/some/url", function (data, response) {
then(err=null, JSON.parse(data));
});
}
}
So you may call getWeatherStatus in such way,
// Somewhere else in your code
getWeatherStatus(function fnCallback(err, jsonData) {
console.log(jsonData) // process data here
})
As suggested, Promise are also a good alternative. but it is still async.
I'm writing an Http Request without the use of a library (another script was having conflits...)
But Im having trouble with the scope of my object. Below is the calling script, then the Ajax_Request object follows.
function loadCard(e) {
var element = e.target;
if($('overlay')) {
return false; //something is already over the layout
}
var card = '/card/'+element.id;
var option = {method:'post', parameters:'test', async:true}
loadOverlay();
var ajax = new Ajax_Request(card, option);
}
//Ajax_Request
function Ajax_Request(url, options) {
if(typeof url !== 'undefined') {
this.url = url;
}
if(typeof options.method !== 'undefined') {
this.method = options.method;
} else {
this.method = 'get';
}
if(typeof options.parameters !== 'undefined') {
this.parameters = options.parameters;
}
if(typeof options.async !== 'undefined') {
this.async = true;
} else {
this.async = false;
}
if(window.XMLHttpRequest) {
this.request = new XMLHttpRequest();
} //check for MS browser
this.makeRequest = function() {
try {
this.request.onreadystatechange = this.checkReadyState;
this.request.open(this.method, this.url, this.async);
if(this.method == 'post') {
this.request.send(this.parameters);
} else {
this.request.send(null);
}
} catch(err) {
alert(err);
}
}
this.setResponse = function(r) {
alert(r)
this.response = r;
}
this.getResponse = function() {
return this.responseText;
}
this.checkReadyState = function(r) {
switch(this.readyState) {
case 4:
//Represents a "loaded" state in which the response has been completely received.
if(this.status == 200) {
this.setResponse(this.responseText)
}
...
}
}
}
I'm trying to set the response to a property so my calling object can work with it.
But when I try to call this.setResponse(), I get an error that it's undefined.
How can I tie the onreadystatechange callback to my program properly?
The script otherwise returns the data properly, and I could simply output it right there, but I need a bit more flexibility.
Thanks
Rich
This is happening to you because inside the checkReadyState function this actually represents the XMLHttPRequest instance not you Ajax_Request object, thus this.setResponse is undefined. In order to reference your object´s method you have to use a little trick: var that = this.
function Ajax_Request(url, options) {
var that = this;
...
this.checkReadyState = function (r) {
switch(this.readyState) {
case 4:
if(this.status == 200) {
// "this" refers to the XMLHttpRequest,
// but "that" refers your custom Ajax object
that.setResponse(this.responseText)
}
...
}
}
}
I'm not sure whether this is the problem, but you shouldn't be referring to Ajax_Request within the constructor. Use this instead. (this refers to the actual object instance—Ajax_Request refers to the object constructor.)
this.makeRequest = function() {
try {
this.request.onreadystatechange = this.checkReadyState;
this.request.open(this.method, this.url, this.async);
if(this.method == 'post') {
this.request.send(this.parameters);
} else {
this.request.send(null);
}
} catch(err) {
alert(err);
}
};
In this.checkReadyState, try changing this.setResponse(this.responseText) to this.setResponse(this.request.responseText);.