I am wondering is it a good practice to make an ajax in an ajax callback function (could be called nested ajax calls?) ? Anyway here is my example
ajax.js
$(document).ready(function() {
$('#button').click(function() {
var string = 'some string';
$.post('ajax-call.php',
{
string: string
}, function(result) {
if(result == 'success') {
// Second ajax call if result returned is success
$.post('second-ajax.php',
{
variable: 'Some Variable'
}, function(second_result) {
if(second_result == 'yes') {
// Do some thing when the second result returned 'yes'
} else {
// Alert error or something
}
});
} else {
// If first result is not success, show a message
}
});
});
});
So basically I have two separate php file that is called on different time, if the first ajax call returned 'success' then proceed to call the second ajax call. Or should I be using one ajax call, one php script, and decide what to do depending on the result of callback ? example below.
ajax2.js
$(document).ready(function() {
$('#button').click(function() {
var string = 'some string';
$.post('ajax-call.php',
{
string: string
}, function(result) {
if(result == 'success') {
// Do something
} else if(result == 'unsuccessful') {
// If first result is not success, show a message
} else {
// Show error message
}
});
});
});
*Note: both php script are quite a heavy and long script which the first script is codes for validating the ajax call, and if everything is validated correctly, proceed to second ajax call to process the datas into database and so on. The first example will make the script much cleaner and neater, but I am wondering if it is good practice to use nested ajax like that ?
All suggestions and comments are greatly welcome. Thank you in advance for enlightening me on this.
Answering the question:
If both ajax calls are two different services and the second call depends on the first response, I'll do it.
If they are standalone services, I'll work with promises and do the callback when both are resolved.
Maybe is not focused on the question itself, but I see weird to make two server calls for just one real action (the second one).
What I'll do is to make just one call. If the validation doesn't pass, return the error. If it passes, call the other php on the server side and return a vlid response to the client.
Server should do the same job, but you save one data transmission from client to server.
That's just an opinion. I hope it helped you.
Related
Have a bit of an issue here. I checked the different answers which seemed related to my problem but cannot seem to get this working.
I've got a page with a link like so :
View
And here's the javascript
var queryResult;
function getData(id, callbackfn){
$.ajax({
type:"POST",
url:"http://url/to/query",
data:{id: id },
success: function(data){
callbackfn(data);
},
error: function(){
return "err";
}
});
}
function showData(id){
getData(id, Callback);
if(queryResult)
{
alert("Yahoooooo !");
}
else
{
alert("Nope !!!");
}
}
function Callback(data){
queryResult = data.length;
}
When clicked for the first time the link launches the alert box and I get "Nope !!!" but any subsequent click will show a "Yahoooooo !"
If I reload the page then again "Nope !!!" for the first time and then it's fine afterwards. So it seems that queryResult is undefined on the first call but first call only. Any idea ?
Thanx
Put your control in Callback function
function Callback(data){
queryResult = data.length;
if(queryResult)
{
alert("Yahoooooo !");
}
else
{
alert("Nope !!!");
}
}
You're using .ajax
this method is asyncronous by default.
So you call "getData" then your Data is loaded.
While it is loaded you check if queryResult exists
Then the data has been loaded and your global flag is set
(At the moment you are checking if the previous request was successful)
The ajax call executes ansynchronously. Therefore when you call getData(), the method call returns instantly (and the ajax call is executing in another thread). This means the first time you click the link, there won't be anything in queryresult because the ajax call hasn't had time to finish before you hit your if block, but the subsequent times there (probably) will be, assuming the call has finished before the next time you click the link.
If you have any logic, such as that if block which depends on the data being returned from the ajax call, you must include it in (or call it from) your callback function.
So in this case you must move the block:
if(queryResult)
{
alert("Yahoooooo !");
}
else
{
alert("Nope !!!");
}
from the getData to the Callback function.
I am pretty new to web programming, so please bear with me.
I created a web page that submits form data to a PHP exec() function. This function requests data (once or multiple times) from a website, manipulates it in various ways, and sticks it in a file on my web server. While processing, a loader .gif file appears on the web page. I have created a piece of JavaScript code to handle the process waiting period, but I'm not sure that I'm doing it right. The script is as follows:
<script>
window.set = 0;
window.uid = '';
document.forms[0].onsubmit = function(e)
{
console.log($(this).serialize());
e.preventDefault();
e.stopPropagation();
// Display "Waiting" .gif during processing
$('#loader').show();
// Perform data submission once (when window.set = 0). After that,
// keep waiting for output and manifest file to be created. Call
// "fetch" function repeatedly to test for completion. When completed,
// call clearInterval to stop processing.
window.int_ = setInterval(function()
{
$.ajax({
"url": "./",
"type": "POST",
"data": !window.set ?$("#form").serialize() : { 'fetch': 1, 'uid': window.uid }}).done(function(data)
{
var d = data = JSON.parse(data);
if (!window.set)
{
window.uid = d.uid;
window.set = 1;
return;
}
if (data.status === 'ok')
{
document.location.replace(data.href);
data.manifest = data.manifest.replace(/\./g, ".<br />");
$('#manifest').show();
$('#manifest').html("<b>Results from run:</b> <br />" + data.manifest);
$('#loader').hide();
window.set = 0;
window.uid = '';
clearInterval(window.int_);
}
else
{
// waiting
}
});
}, 100);
}
</script>
The code for the "fetch" function referenced in the first AJAX call is as follows:
if ($_POST['fetch'])
{
$uid = $_POST['uid'];
/* check for availability*/
if (is_file(realpath("./$uid")))
{
$f = file_get_contents($uid);
$m = file_get_contents("./$uid.manifest");
}
else
{
$f = "";
}
if ($f != "")
{
echo json_encode(array("status" => "ok", "href" => $f, "manifest" => $m));
die();
}
else
{
echo json_encode(array("status" => "err", "href" => $f));
die();
}
}
What I'm trying to do here is perform the external website processing/manipulation one time, while waiting for the processing to be finished. The "fetch" function checks to see if my output file has been created. If it has, processing ends.
Is this a programmatically sound approach to this problem? Are there alternatives that would be much better?
I would greatly appreciate any insight you can provide. I really want to learn the right way to do things.
I try to make an easy explain of HTTP Requests...
At first you have your Backend code on a Webserver, in your case written in php. This Script doesnt do anything else, then process the data you send to it and maybe post (echo) a failure, or succeed of its processing back to the frontend client. In your case thats all.
On Frontend side its almost the same procedure, whatever language or device you take.
You invoke a HTTP POST or GET request in an asynchronous task, in your case jQuery does that for you by calling its $.ajax function to your php.
Also in that request, you define a callback function which will be invoked automatically, after async processing is finished. jQuery does that for you too, its the .done() function right after the $.ajax.
To indicate loading, the best way would be to Show your loading image right before the $.ajax line of code... And hide or remove it inside the .done() function... To indicate loading is done...
Thats all.
I have two forms ('table' and 'fields'). The 'fields' form is supposed to pre-populate with options depending on the choice made in 'table', by making an Ajax request.
The data is returning perfectly and actually prepopulates the second form (like it should) if I pass a cut-and-paste example of some returned data to a local variable (see commented line).But for some reason it won't work on the returned object??
Any advice would be appreciated as I am very new to JavaScript and am probably missing something blatantly obvious! I am using the following code:
$(document).ready(function() {
$('select#table').change(function(){
$.getJSON("/ajax_get",{id: $(this).val(), ajax: 'true'}, function(data) {
//var data = [{"optionValue":"address", "optionDisplay": "address"},{"optionValue":"latitude", "optionDisplay": "latitude"},{"optionValue":"longitude", "optionDisplay": "longitude"},];
var $persons = $('#fields').empty();
$.each(data, function() {
$persons.append("<option value=" + this.optionValue + ">" + this.optionDisplay + "</option>");
});
});
});
});
Here's a simplified version of your call that should help you figure it out quickly:
$.getJSON("/ajax_get",{id: $(this).val(), ajax: 'true'}, function(data) {
try {
typeof(data.somethingYouExpect);
/* do your on success work here */
} catch (e) {
alert('There is a good chance the response was not JSON');
}
});
Even when using the regular jQuery $.ajax call, it's important to check to be sure the returned response is in the form you expect. This is as simple as setting a variable like success in your response as true. If you did that, the above example becomes something like this:
var jqxhr = $.getJSON("/ajax_get",{id: $(this).val(), ajax: 'true'}, function(data) {
try {
typeof(data.success); // Will throw if success is not present
if (success == true) {
/* handle success */
} else {
/* handle a request that worked, but the server said no */
}
} catch (e) {
/* The actual HTTP request worked, but rubbish was returned */
alert('There is a good chance the response was not JSON');
console.dir(jqxhr.textResponse);
}
});
Here, we remember the object returned by the $.getJSON call (which is just a shortcut to $.ajax), which allows us to view the actual response sent by the server. I'm willing to bet it's a 404, parser error or something of that sort.
For most things, I usually just use $.ajax mostly out of personal preference, where the error callback passes the xhr object to a common function to examine (did the request return 200? etc). If something explodes, I know exactly what went wrong by briefly looking at the console and can disable debug output in one place.
I have the following code which is included in a keypress function:
$.getJSON('dimensions.json', function(data) {
$.each(data, function(index) {
$('#div1').append(index);
});
});
I'm trying to first get the JSON string, save it in a variable and then run the each(). I want to basically separate the each() to be unlinked to the getJSON() function because I don't want it to fetch the json file for every keypress.
I've tried this, but it didn't work:
var JSONstr = $.getJSON('dimensions.json');
$.each(JSONstr, function(index) {
$('#div1').append(index);
});
In your first example, you do $.each in the callback. The callback is executed by some other callback after there result is received, while $.getJSON returns immediately without waiting for the result (since there is no blocking in JavaScript by design).
Therefore the code in your second example can never work: the $.each begins before any result is received from the web server, probably even before the request is sent. Whatever the return value of $.getJSON is, it can't, by the design of JavaScript, be the result of AJAX request.
UPD: Saw your comment, now I understand what you wanted to do. Here's a simple example of how to do this:
function ActualHandler(data) {
$.each(data, function(index) {
$('#div1').append(index);
});
}
function KeypressHandler() {
if (window.my_data) { // If we have the data saved, work with it
ActualHandler(window.my_data);
}
else { // Otherwise, send the request, wait for the answer, then do something
$.getJSON('dimensions.json', function(data) {
window.my_data = data; // Save the data
ActualHandler(data); // And *then* work on it
});
}
}
Here, the ActualHandler is not launched before the data is received, and once that happens, all subsequent clicks will be handled immediately.
The downside in this particular case is that if user clicks again while the first request is running, one more will be sent. But to fix that you would need to maintain some queue, which is kind of out of scope here.
You fell into the asynchronous trap. Your $.each() function doesn't wait for your $.getJSON() call to get the data. You can get around this by using the good 'ol $.ajax() function. Like this:
function processJSON(data) {
$.each(data, function(index) {
$('#div1').append(index);
});
}
$.ajax({
url: 'dimensions.json',
dataType: 'json',
async: false,
success: processJSON(data)
});
I am trying to write a JavaScript interface for an Api, but I can not figure out this issue. I have code to call an ajax request:
mooshark.request('userInfoFromID', {
userID : '20991'
});
That code creates an Ajax request. When it starts, it sets an internal variable to true (to indicate that it is running). Then on the next line I have this:
var data = mooshark.response();
alert(data);
The response function is as follows:
response: function () {
if(this.running == false){
return "done";
} else if (this.running == true){
alert("Running");
setTimeout(this.response, 3000);
}
}
It outputs (in this order) Running. undefined. (JSON response). Running. Not once does it output "done". Is there a way to return "done" when this.running becomes true? I would like to mention that this.running will not always be the same request time. I know there is always the option of wrapping all my code inside the onCompleat function in the ajax request, but I want to have that as a last resort.
Thanks!
This is not possible without freezing the browser.
Whenever your code is running, the browser UI will be completely frozen.
If you want the call to wait for the server to reply, the browser will need to be competely frozen. (which is not a good idea)
Since most of the time you're calling response() through setTimeout(), a return value isn't really useful.
But -- you're likely never setting your 'running' variable to false. You might post more code here (the AJAX response handling code, for example). Also: what exactly are you trying to accomplish by returning / alerting "running" and "done"?