AJAX call finishes after rest of the script - javascript

I Have an AJAX call to get entry's of a list from a database. So I recieve the Data from my Ajax call, but they are a little bit to "late" so the rest of the actions start before the neccessary data is fully loaded (see screenshot). Is there a way to pause the script until the ajax data is fully loaded to use all of the information? Does this happen because of the "asynchronus = true" ?
Would be nice to get some answers, Thanks!
Console shows this:
I tried to re-order the script, but nothing really changed the problem.
var data_array = [];
var data = [];
var output = document.getElementById('entry-list');
/*Static Data Variables for Data Call*/
var name;
var priority;
var category;
var expiry;
/*Call AJAX*/
var ajax = new XMLHttpRequest();
var method = "GET";
var url = "getdata.php";
var asynchronous = true;
ajax.onreadystatechange = function()
{
if (this.readyState == 4 && this.status == 200) {
/*getting return --> putting/convert json into array*/data.push(JSON.parse(this.responseText));
console.log(data.length);
for(var a = 0; a<data.length; a++){
name = data[a].name;
priority = data[a].priority;
category = data[a].category;
expiry = data[a].expiry;
data_array.push("<li class='' id='list-item"+a+"' onclick='itemClick(this)'>"+name+" #"+a+", "+priority+"</li>");
console.log("Array-entry added");
}
}
}
ajax.open(method, url, asynchronous);
//sending
ajax.send();
//recieving asnwer from getdata.php
console.log(data_array);
output.innerHTML = data_array;

Is there a way to pause the script
You're thinking about this the wrong way. Instead of trying to force operations to be blocking, instead re-structure your code to use the data in response to the asynchronous operation. Basically, the lines after //recieving asnwer from getdata.php should be in the callback function, not after it.
So instead of something like this:
ajax.onreadystatechange = function()
{
// the rest of your code
}
ajax.open(method, url, asynchronous);
ajax.send();
console.log(data_array);
output.innerHTML = data_array;
You would do something like this:
ajax.onreadystatechange = function()
{
// the rest of your code
console.log(data_array);
output.innerHTML = data_array;
}
ajax.open(method, url, asynchronous);
ajax.send();
Naturally, your code could get larger and more complex than just those two lines. How you structure the more complex operations is up to you. But the point is that those operations should be invoked by the response handler for the AJAX function.

You can do it this way with jquery AJAX.
$.ajax({
method:"POST",
url:"URL",
data: {name:value},
success: function (responseText) {
//CODE HERE RUN AFTER DATA FULLY LOADED
}
});

Related

How to Send Ajax Request After A Specific Time

How to Send Ajax Request in specific time and only that particular event
I m User Time Interval But it’s not Working.
i want get data in request 1 for use in request 2 but it get null data in request 2
setInterval()
it's not Working for me.
I want To send Request 2 After the some time of Request 1
Request 1:-
$(document).on("change", ".supplyItem", function (event) {
var id = $(this).attr("data-id");
var supplyItem = $(".supplyItem[data-id=" + id + "]").val();
var hospital = $("#hospital").val();
var physician = $("#physician").val();
var category = $("#category").val();
var manufacturer = $("#manufacturer").val();
var project = $("#project").val();
if (hospital != "" && physician != "" && category != "" && manufacturer != "" && project != "") {
$.ajax({
url: "{{ URL::to('admin/repcasetracker/getitemfile')}}",
data: {
supplyItem: supplyItem,
hospital: hospital,
project: project,
},
success: function (data) {
console.log(id);
if (data.status) {
var html_data = '';
var item = data.value;
console.log(item);
$('.hospitalPart[data-id=' + id + ']').val(item.hospitalNumber);
$('.mfgPartNumber[data-id=' + id + ']').val(item.mfgPartNumber);
// $('.mfgPartNumber[data-id='+id+']').text('something');
} else {
$('.hospitalPart[data-id=' + id + ']').val('');
$('.mfgPartNumber[data-id=' + id + ']').val('');
}
$('.quantity[data-id=' + id + ']').val('');
$('.purchaseType[data-id=' + id + ']').val('');
$('#serial-text' + id).val('');
$('#serial-drop' + id).val('');
$('#serial-drop' + id).empty();
}
});
}
});
Request 2:-
$(document).on('change', '.supplyItem', function (event) {
var timer, delay = 2000;
var id = $(this).attr("data-id");
var client = $("#hospital").val();
timer = setInterval(function(){
var supplyItem = $(".supplyItem[data-id=" + id + "]").val();
var hospitalPart = $(".hospitalPart[data-id=" + id + "]").val();
var mfgPartNumber = $(".mfgPartNumber[data-id=" + id + "]").val();
alert(supplyItem);
alert(hospitalPart);
alert(mfgPartNumber);
$.ajax({
url: "{{ URL::to('admin/repcasetracker/getdevicedata')}}",
data: {
supplyItem: supplyItem,
hospitalPart: hospitalPart,
mfgPartNumber: mfgPartNumber,
client: client,
},
success: function (data) {
if (data.status) {
var html_data = '';
var check = data.value;
if (check == 'True') {
html_data += "<option value=''>Purchase Type</option><option value='Bulk'>Bulk</option><option value='Consignment'>Consignment</option>";
$('.purchaseType[data-id=' + id + ']').html(html_data);
} else {
html_data += "<option value=''>Purchase Type</option><option value='Consignment'>Consignment</option>";
$('.purchaseType[data-id=' + id + ']').html(html_data);
}
}
}
});
}, delay);
clearInterval(timer);
});
You can move Request 2 into a function and this JS code will call the Request2 function after given interval of time (milliseconds), I have set it to 5 seconds for now.
setInterval(function () { Request2(); }, 5000);
function Request2(){
console.log("Request 2 called");
//add request 2 code here
}
jQuery's $.ajax method returns a promise, which is passed the result of the server-side call. You can chain these calls together so that you can build the result of multiple ajax calls. When you use it this way you do away with success callbacks as they are no longer necessary.
Applied to your code it might looks something like this:
$(document).on("change", ".supplyItem", function (event) {
var id = $(this).attr("data-id");
var supplyItem = $(".supplyItem[data-id=" + id + "]").val();
var hospital = $("#hospital").val();
var physician = $("#physician").val();
var category = $("#category").val();
var manufacturer = $("#manufacturer").val();
var project = $("#project").val();
if (hospital != "" && physician != "" && category != "" && manufacturer != "" && project != "") {
$.ajax({
url: "{{ URL::to('admin/repcasetracker/getitemfile')}}",
data: {
supplyItem: supplyItem,
hospital: hospital,
project: project,
})
.then(function(data1){
// process result of call1 and make call2
var item = data1.value;
return $.ajax({
url: "{{ URL::to('admin/repcasetracker/getdevicedata')}}",
data: {
supplyItem: supplyItem,
hospitalPart: value.hospitalPart, // note using result from 1 directly
mfgPartNumber: value.mfgPartNumber,
client: hospital
}
});
})
.then(function(data2){
// process result of call2
});
};
});
The point here is that you don't need to stash the result of call1 into some elements and re-read them before making call2, and trying to wait enough time before making call2. You just chain it all together with then.
Ok first though: Instead of using setInterval and then clearing the interval after it has run a single time, why not just use
setTimeout(function, delay);
Then personally I prefer to use XMLHttpRequest instead of Jquery AJAX, Jquery uses XMLHttpRequest at its base anyway,I just prefer it so I dont have to use Jquery, but if your already using Jquery in your site then it should be no more heavy. Here is a quick example of XMLHttpRequest so u can use it if you prefer.
var xhr = new XMLHttpRequest();
xhr.open("POST", 'URL::to("admin/repcasetracker/getdevicedata")', true);
xhr.setRequestHeader("Content-Type", "application/json charset=utf8");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
// content is loaded...
if (xhr.responseText) {
//Some code to run after the server responds and it was successfull
}
}
};
xhr.send(JSON.stringify({test:'test'})); //This is the data you are handing to the server
Notice the use of xhr.responseText, JQuery uses the same variable and this is usually the response from the server. One sure way to know is use your browser's debugging engine (F12 on Chrome and Firefox, have no idea on other browsers) to inspect the variables, it is very easy to ascertain the correct variable to use.
And then one last thought: I see you are not declaring the content-type and not JSON.stringify'ing() your data when you send it to the server.
Best way to debug a situation like this is 'proccess of elimation' so find out if the server is receiving the data then if the server is proccessing the data correctly and then check if the server is sending the data correctly.
If you are using Nginx use the /var/log/nginx/error.log to see if it throws any errors ( tip: tail -f /var/log/nginx/error.log | Apache uses /var/log/http/error.log on most distros ) and if you are using .NET just debug it in Visual Studio.
And read up on the Jquery success event there is 2 more arguments that gets passed - String textStatus and jqXHR jqXHR
http://api.jquery.com/jquery.ajax/
So to summarize:
Make sure to declare the dataType: 'json'
Use the correct variable, should be responseText
when passing the server data and using 'json' make sure to JSON.stringify() it
And I don't quite see why you want to use setTimeout in the first place.
If you are simply waiting for the server to respond then using any type of delay will be a terrible idea, instead use the events that gets fired after the server responds.
So in Jquery that is success: function() {} and error: function() {}
and in XMLHttpRequest its the xhr.onreadystatechange = function () { }

AJAX calls inside a loop

So, I have a list of data that I am out putting onto my view, and each list item has an id.
Each of these list items is a bar and I have a document created for each bar that at least one user is going to. For those bars where no users are going, there is no document created.
I need to make an AJAX call for each list item to the database to check
i) If a document exists for that list item
ii) If a document exists, how many users are going according to the document.
I attempted a solution using a while loop, where the update for the while loop was contained in the callback for the AJAX call. Here is the code
function updateAllGoingButtons(){
var i = 0;
var dataToPass = {};
var numButtons = global_data_object.listData.businesses.length;
while(i < numButtons){
dataToPass.button = global_data_object.listData.businesses[i].id;
dataToPass = JSON.stringify(dataToPass);
ajaxFunctions.ready(ajaxFunctions.ajaxRequest('POST', '/update-buttons', dataToPass, function(data){
console.log(i);
i++;
}));
}
}
When I attempted to run the function, I got the error,
Request entity too large
So, is there a better way to go about doing what I am trying to do? Should I use promises? Or is there simply an error in the way I am trying to make the AJAX call from within a while loop?
For reference, here is the ajaxRequest function
'use strict';
var appUrl = window.location.origin;
var ajaxFunctions = {
ready: function ready (fn) {
if (typeof fn !== 'function') {
return;
}
if (document.readyState === 'complete') {
return fn();
}
document.addEventListener('DOMContentLoaded', fn, false);
},
ajaxRequest: function ajaxRequest (method, url, data, callback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
callback(xmlhttp.response);
}
};
xmlhttp.open(method, url, true);
xmlhttp.setRequestHeader('Content-type', 'application/json');
xmlhttp.send(data);
}
};
You should check out the npm library called async, it has an each method that you can do asynchronous calls within. If you use promises, the Promise.all method in Bluebird could be very useful for you.
So, here's how I did the multiple AJAX calls from within a loop. I used this resource https://medium.com/coding-design/writing-better-ajax-8ee4a7fb95f#.d7ymg99mp (Great resource!)
Here's the code
$('.btn-group').find('button').each(function() {
console.log($(this).attr('id'));
dataToPass.button = $(this).attr('id');
var ajax = $.ajax({
url: '/update-buttons',
method: 'post',
data: dataToPass,
dataType: 'json',
}).success(function(data){
console.log(data);
});
});
Essentially, what this does is selects a div with the class 'btn-group' and then iterates over each button within that div using the jQuery each operator. Then simply make an AJAX request and use the success chain callback to access the returned data.

Parsing arguments to functions involving ajax

I am having an issue trying to improve the functionality of my ajax functions by adding arguments to define what to do with the returned result.
So what i am trying to implement is a way to tell the function to append the result to a given element by its id. But i am having difficulty understanding how to add this functionality.
This is my current code:
var ajax = new function(){
var self = this;
self.x = function() {
if (typeof XMLHttpRequest !== 'undefined') {
return new XMLHttpRequest();
}
};
self.send = function(url, callback, method, data, sync) {
var x = self.x();
x.open(method, url, sync);
x.onreadystatechange = function() {
if (x.readyState == 4) {
callback(x.responseText)
}
};
if (method == 'POST') {
x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
}
x.send(data)
};
self.get = function(url, data, callback, sync) {
var query = [];
for (var key in data) {
query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
}
self.send(url + (query.length ? '?' + query.join('&') : ''), callback, 'GET', null, sync)
};
};
I then make an ajax request like so:
//get the html file, and then call a function
ajax.get(dir.layout+'login.html',false,
function(){
elements.addTemplate(data,'parent',true);
});
In Chrome the xhr shows the correct data and contents, so i know that part works. In my elements.loadTemplate function i have these three lines with their actual values:
elements.addtemplate(data,div_id,append){
console.log(data); //shows:
console.log(div_id); //shows string: parent
console.log(append); //shows: true
}
Now the issue is data is blank, when i want it to contain the contents of the HTML file that I just requested (in this case login.html). I am wondering why it would show up as blank and how i can fix it?
your data is undefined because your callback doesn't accept a parameter
try this:
ajax.get(dir.layout+'login.html',false,
function(data){ // <=== data
elements.addTemplate(data,'parent',true);
});

Use data from two separate JSON files in one function

I have two local JSON files that I'm trying to access in a function in my main.js file. Everything works fine with just one JSON file, but I'm not sure how to incorporate the second. Ideally, something like data_set1=$.getJSON("file1.json") would work perfectly, but I see similar questions have been repeatedly asked and because of asynchronous calls, that's not necessarily possible (I don't completely understand all the answers to those questions).
This works as it is:
$.getJSON("data.json", function(json){
var data_points = [];
for (i = 0; i < json.length; i++){
data_points.push([json[i].name, json[i].age]);
}
$(function () {
//do stuff with data_points
but I don't know how to incorporate the second JSON call to make another list for the function at the end to use.
You can use jQuery deferred loading.
var xFile, yFile;
var requestX = $.getJSON("data1.json", function(json){
xFile = json;
});
var requestY = $.getJSON("data2.json", function(json){
yFile = json;
});
$.when(requestX, requestY).then(function(){
// do something;
// this function only gets called when both requestX & requestY complete.
});
Check out JQuery WHEN
An ajax request is ONE request for ONE resource. You can't fetch two different resources with the same request. You'd either need TWO requests:
var completed = 0;
$.getJSON('file1.json', function(json) {
completed++;
if (completed == 2) { all_done(); }
}
$.getJSON('file2.json', function(json) {
completed++;
if (completed == 2) { all_done(); }
}
function all_done(...) { ... }
Or simply combine your two json files into a single one on the server:
{"file1":{data from file one here}, "file2":{data from file two here}}
and access them as data.file1 and data.file2 in your code.
You could just set a var to indicate the file is loaded and call the same function while checking the status. This might be a bad idea depending on the amount of data in the JSON.
var xFileLoaded = false, yFileLoaded = false;
var xFile, yFile;
$.getJSON("data.json", function(json){
xFile = json;
xFileLoaded = true;
doSomething();
});
$.getJSON("data.json", function(json){
yFile = json;
yFileLoaded = true;
doSomething();
});
function doSomething() {
if(xFileLoaded && yFileLoaded) {
// good to go
}
}
Using something very similar to #MarcB's solution, I would keep the files in an array and generalize things slightly:
var files = ["file1.json", "file2.json"];
var results = {};
var completed = 0;
function afterEach(fileName, json) {
results[fileName] = json;
if (++completed >= files.length) {
afterAll();
}
}
files.forEach(function (file) {
$.getJSON(file, afterEach.bind(this, file));
});
This should request all files in parallel, allowing the browser to choose how many connections to actually open and download. After each finishes, the results (json) are put in a hash for storage, under the filename. After all files have completed (assuming files doesn't change), then afterAll function will be called.
It exists with jquery an elegant way to do this :
$.when(
$.ajax({
url: 'file1.json/',
success: function(data) {
// Treatement
}
}),
$.ajax({
url: 'file2.json',
success: function(data) {
// Treatement
}
})
).then( function(){
// Two calls are completed
});
Once the two calls are completed, you can do any manipulation in the block "then".

Use jQuery to replace XMLHttpRequest

I am quite new to JavaScript libraries. I wanted to replace my current code with jQuery. My current code looks like this:
var req;
function createRequest() {
var key = document.getElementById("key");
var keypressed = document.getElementById("keypressed");
keypressed.value = key.value;
var url = "/My_Servlet/response?key=" + escape(key.value);
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.open("Get", url, true);
req.onreadystatechange = callback;
req.send(null);
}
function callback() {
if (req.readyState == 4) {
if (req.status == 200) {
var decimal = document.getElementById('decimal');
decimal.value = req.responseText;
}
}
clear();
}
I wanted to replace my code with something a little friendlier like jQuery's
$.get(url, callback);
However it doesn't call my callback function.
Also I would like to call a function called createRequest continuously. Does jQuery have a nice way of doing that?
­­­­­­­­­­­­­­­­­­­­­­­
$.get(url, {}, callback);
should do the trick. Your callback could be simplified like this:
function callback(content){
$('#decimal').val(content);
}
Or even shorter:
$.get(url, {}, function(content){
$('#decimal').val(content);
});
And all in all I think this should work:
function createRequest() {
var keyValue = $('#key').val();
$('#keypressed').val(keyValue);
var url = "/My_Servlet/response";
$.get(url, {key: keyValue}, function(content){
$('#decimal').val(content);
});
}
Take out the readyState and status checks. jQuery only calls your callback upon success. Your callback is supplied the arguments (data, textStatus), so you should use data instead of req.responseText.
window.setTimeout() as suggested by another answer won't do what you want - that only waits and then calls your function once. You need to use window.setInterval() instead, which will call your function periodically until you cancel it.
So, in summary:
var interval = 500; /* Milliseconds between requests. */
window.setInterval(function() {
var val = $("#key").val();
$("#keypressed").val(val);
$.get("/My_Servlet/response", { "key": val }, function(data, textStatus) {
$("#decimal").val(data);
});
}), interval);
I don't think jQuery implements a timeout function, but plain old javascript does it rather nicely :)
According to the docs, jQuery.get's arguments are url, data, callback, not url, callback.
A call to JavaScript's setTimeout function at the end of your callback function should suffice to get this to continually execute.
There's no need to set the GET parameters on the URL, jQuery will set them automatically. Try this code:
var key = document.getElementById("key");
[...]
var url = "/My_Servlet/response";
$.get (url, {'key': key}, function (responseText)
{
var decimal = document.getElementById ('decimal');
decimal.value = responseText;
});
In the end I guess it was added the type. This seems to work for me.
function convertToDecimal(){
var key = document.getElementById("key");
var keypressed = document.getElementById("keypressed");
keypressed.value = key.value;
var url = "/My_Servlet/response?key="+ escape(key.value);
jQuery.get(url, {}, function(data){
callback(data);}
, "text" );
}
function callback(data){
var decimal = document.getElementById('decimal');
decimal.value = data;
clear();
}
Thanks Everyone for the help. I'll vote you up.

Categories

Resources