This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I have never been very good at understanding JS callbacks, promises and all of these. Now I stumbled on one of these scenarios.
I have a text element. When clicked, it is made editable. When pressing enter, an AJAX request is made with the input value and then (here is my issue) the original text should be updated with the input.
$('#text-element').click(function() {
edit($(this), url, paramName);
});
function edit($element, url, paramName) {
// show the input, set up some UI events...
$input.keypress(function(key) {
// check if it is the correct key to submit the data
if (submit) {
var data = {};
data[paramName] = $input.val();
$.ajax({
url: url,
method: 'post',
data: data,
success: function(response) {
// ???
}
});
}
});
}
You could say: simple, just take the data from the response and replace the original text with the updated one. I can't/don't want to do that because I want the edit function to stay generic so it can be used in other scenarios, as you might have guessed by the use of the different arguments.
Also, in the context of the edit function we don't really know the shape of the response object, so we cannot handle it at that stage.
The right place where the response should be handled is the part where we click the text element, here we do know the context and we know the expected composition of the response.
So essentially, I would want to return (or whatever you do when dealing with promises, callbacks, async operations...) the response from the ajax success function, fetch that response in the click handler funtion and deal with it accordingly:
$('#text-element').click(function() {
edit($(this), url, paramName); // <--- this should "return" the response
var response = ...; // how do I fetch this response from the edit function
$(this).html(response.content); // the response we expect in this case would be a JSON response with a key "content"
});
I hope I could make myself understand. If I don't, please let me know so I can clarify the question.
Simply make a callback function:
$('#text-element').click(function() {
edit($(this), url, paramName,function(response){
this.html(response.content);
}.bind($(this)));//bind to keep the #text-element as this
});
function edit($element, url, paramName,callback) {
// show the input, set up some UI events...
$input.keypress(function(key) {
// check if it is the correct key to submit the data
if (submit) {
var data = {};
data[paramName] = $input.val();
$.ajax({
url: url,
method: 'post',
data: data,
success: function(response) {
callback(response);//whats your problem with callbacks? they are so easy...
}
});
}
});
}
By the way, if the user clicks twice, there are two keypress handlers registered, making the whole code a mess. So you may prevent that in a way...
Related
This question already has answers here:
Javascript - Stop form submit depending on ajax response [duplicate]
(2 answers)
jQuery preventDefault() not working inside AJAX call
(6 answers)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 1 year ago.
I'm looking for a way to modify a variable declared outside of a callback, then use the modified variable after defining the callback. My intent is reflected in the code:
$('#my_form').submit(function() {
let my_condition
let data = $(this).serialize()
$.ajax({
method: 'POST',
url: '/my_url',
data: data
})
.done(function(json_response) {
if (json_response.my_variable) {
my_condition = true
}
else {
my_condition = false
}
})
// I'm looking for a way to guarantee `my_condition` is set by the AJAX before the below code is run.
if (my_condition) { // I know `my_condition` will be null because this line won't wait for the AJAX to finish and set `my_condition`.
return true
}
else { // The event handler will always hit this condition.
return false
}
})
I'm aware that I could add blocking sleep time before checking my_condition to wait for the AJAX. This is not a solution I'm looking for. I'm also aware that I could set my_condition based on inspecting data on the frontend. However, for reasons specific to my use case, data needs to be processed on the backend. Lastly, I want to avoid the AJAX setting async: false.
I know why the code above does not work. My question is, is there some way to achieve the desired result? I have a feeling there might be a solution that uses Promise, but I don't see exactly how that would be done.
Edit 1: The specific use case is with regards to form submission. I want the submit handler to return true or false, i.e., submit via the form's action attribute (when my_condition is true) or a different (AJAX) route (when my_condition is false) based on backend processing results of data.
Edit 2: This is indeed a duplicate of Javascript - Stop form submit depending on ajax response [duplicate]
I suspect (although specific problem is not clear) you want the form to submit only if you get a valid response in the ajax.
You can prevent the initial submit and then submit the form inside the done callback if condition is met.
$('#my_form').submit(function(e) {
// prevent submit
e.preventDefault()
let form = this;
let data = $(form).serialize()
$.ajax({
method: 'POST',
url: '/my_url',
data: data
})
.done(function(json_response) {
if (json_response.my_variable) {
// trigger native submit, will bypass this jQuery submit listener
form.submit()
}
else {
// do something else
}
})
})
I have what might be a tricky question.
I am working on a form where it verifies a couple things on submit, using event.preventDefault(); to prevent the form from submitting if something went wrong. The issue here is that it sends multiple ajax requests at the same time, which seems to stop the php (which is processing the AJAX call) from modifying the $_SESSION variable.
I have determined this by changing the jquery ajax calls to process synchronously, allowing the $_SESSION variable to be changed.
My question is this: is there a way to allow the ajax calls to happen synchronously while allowing the $_SESSION variable to be modified during the process of those calls? I realize that the async:false for an AJAX call is deprecated, and obviously not the best solution.
Due to what each call does, it is not possible to combine the functionality of these two calls, although each call does not take long at all to process.
Example jquery code to explain how I am making these AJAX calls (some redaction and simplification, obviously):
$("#form-id").on('submit', function(event) {
$.ajax({
type: 'POST',
url: '/url/to/processing.php',
async:false, //fails without setting to false
...
});
});
...
$("#form-id").on('submit', function(event) {
$.ajax({
type: 'POST',
url: '/url/to/processing2ThatSetsSession.php',
async:false, //fails without setting to false
...
});
});
You have to concat the calls, to run one call after the other has ended.
I'll do it this way:
function ajaxPost(url, callback) {
$.ajax({
type: 'POST',
url: url
...
}).done(callback);
}
$("#form-id").on('submit', function(event) {
event.preventDefault(); // Always stop the event
// Do one ajax call and wait for the data
ajaxPost('/url/to/processing.php', function(data) {
// Do things with returned data and call the next ajax
ajaxPost('/url/to/processing.php', function(moredata) {
// Do something with moredata
// If everything is fine, re-post it but this time do not catch the event
$("#form-id").off("submit").submit();
});
});
});
You can add your own logic to show your error message in any callback and not continue with the next one.
With this I'll do an special method for multiple ajax form validation:
// This function will get an array of objects and
// do an ajax call and process the data, one after another
function multiAjax(calls, callback) {
var call = calls.shift();
if (call) {
var url = call.url;
post(url, function(data) {
var error = call.process(data);
if (error) {
callback(error);
} else {
multiAjax(calls, callback);
}
});
} else {
callback();
}
}
// This is the array of objects that multiAjax will process.
// You can add or remove elements to your likings, without modifying
// the submit event callback
var ajaxArray = [{
url: '/url/to/processing.php',
process: function(data) {
if (data.isWrong()) {
return "The data is wrong";
}
}
}, {
url: '/url/to/processing.php',
process: function(data) {
if (data != "OK") {
return "The data is not OK";
}
}
}];
// Now listen for the submit event
$("#form-id").on('submit', function(event) {
// Always stop the event
event.preventDefault();
// Do multiple ajax calls in one function call.
// Because the array is mutated inside multiAjax() (yeah, bad design but I've
// done this fast as an example), we slice() the array to get a new one
multiAjax(ajaxArray.slice(), function(error) {
if (error) {
// Show the error received
} else {
// submit the form the same way above
$("#form-id").off("submit").submit();
}
});
});
This is all untested code, but you get the point.
If one form submission is making two posts to the same PHP server, you should rethink the architecture instead of building complicated workarounds.
I would POST to a single PHP script that will do everything you need in the backend.
$.ajax({
type: 'POST',
url: '/url/to/all-processing.php',
... // send all the data needed by all processes
});
On the PHP side: all-processing.php
session_start();
require_once './process1.php';
require_once './process2.php';
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I have a few functions that grab data using ajax and I can then get the result data from outside the function when needed.
Here is one example:
function myfunction() {
jQuery.ajax({
url: someurl
method: 'GET',
async: false,
success: function(result) {
myresult = result;
}
});
return myresult;
};
And this from outside I get the data like this:
myvar = myfunction();
Doing it this way I am able to get the data outside the function.
I have searched google and stackoverflow and I still can't understand it so I thought adding a function that I'm already using might help me understand better how to do this.
How can I convert this code so that when I set async to true I'm able to get the data from outside the function?
How can I convert this code so that when I set async to true I'm able to get the data from outside the function?
Simple answer, don't. You're approaching the problem in the wrong way.
Instead of trying to get data available outside the function, you could provide a callback function which the data should be passed to:
function myfunction(callback) {
$.ajax({
url: someurl
method: 'GET',
success: callback
});
};
myfunction(function(data) {
// work with the data retrieved from the async request here...
console.log(data);
});
Note: this pattern is a little redundant in this example as you could just give the anonymous function directly to the success property. In a real scenario you'd probably want to execute some actual generic logic in the success handler before calling the provided callback function.
Alternatively you could return the deferred object from the jQuery AJAX request and then use a done() handler to be executed when the object is resolved:
function myfunction() {
return $.ajax({
url: someurl
method: 'GET'
});
};
myfunction().done(function(data) {
// work with the data retrieved from the async request here...
console.log(data);
});
In either case the logic to follow is that the data from the request should be provided to the required function instead of being made globally available.
First of all I've read this question which I found very usefull.
I'm trying to detect if an url is responding. If so then use this url and start another function if false then create a new url and start an other function.
I tried to implement the code from the question mentioned above but I found it difficult to incorporate that in my code since I do not understand what he tries to mention with the callback.
So what I have is two functions:
function relatedProducts(relatedUrl){
$.getJSON(relatedUrl, function(data){
......
});
}
function liveSearch(liveSearchUrl){
$.getJSON(liveSearchUrl, function(data){
......
});
}
Further I have an variable url and I'm trying to test if that url is responding so not if it is valid.
var url ='apple/i-phone/iphone5';
function urlExists(url, exists){
$.ajax({
type: 'HEAD',
url: url,
success: function(){
// what do I have to do here???
Poster is mentioning `callback` but which one??
},
error: function(){
// what do I have to do here???
Poster is mentioning `callback` but which one??
}
});
}
urlExists(url, function(exists){
if(true){
var relatedUrl = ??
relatedProducts(relatedUrl);
} else {
var liveSearchUrl = ??
liveSearch(liveSearchUrl);
});
I'm still learning jQuery and I'm pretty confused by the poster and his answer ;)
Any help greatly appreciated.
AJAX is asynchronous and so calls to AJAX methods are non-blocking. So you can't expect any results from an AJAX method to be available when the control flow is returned to the caller and subsequent function calls should not rely on the AJAX call having completed.
Simple example:
doSomeStuff($.ajax(...)); //doesn't work
Other example:
var x = false;
$.ajax({
url: url,
success: function(){
x = true;
}
});
if (x) {
// probably doesn't work
}
That's where the callback functions come in: You can tell a call to an AJAX method to do some stuff once it is finished. Those are the success and error parameters in your example.
Now for your specific example. I realize you copied most of it from an answer to a similar question, but I see several problems with it, amongst other things your use of if (true), which is not what you want there, so here's my shot at improving that code:
First, we need 2 callbacks instead of one, there's no need to force one method to do what was clearly intended to be handled by 2 different methods.
var successCallback = function() {
var relatedUrl = '' // see note below code block
relatedProducts(relatedUrl);
}
var errorCallback = function() {
var liveSearchUrl = ''// see note below code block
liveSearch(liveSearchUrl);
}
Next, let's change your urlExists
function urlExists(url, sCallb, eCallb){
$.ajax({
type: 'HEAD',
url: url,
success: sCallb,
error: eCallb
});
}
And finally, this is how you put those pieces together:
var url ='apple/i-phone/iphone5';
urlExists(url,successCallback,errorCallback);
Some notes:
If you want relatedUrl and liveSearchUrl to be the same URL that was used for the ajax call, let me know and I'll change my example accordingly. If not, just put the url you want to use inside the quotes.
Of course, urlExists is a wrapper that's not even needed, you could use your url and the callbacks directly in the AJAX call, but this way it's much cleaner to look at, easier to understand and far more reusable.
This code will execute errorCallback for ANY error, and successCallback if no error occurred. This may actually not be what you want, especially if you consider that AFAIK 3xx status codes are considered an error. To get much finer control, you can define callbacks for each status code, or just for some of them, if you want I can update my example, let me know.
Please check this.It same like nob.
var callback = function (x){
if(x)
alert ("You can make real call to this url");
else
alert ("Somthing worng");
};
$.ajax({
type: 'HEAD',
url: "/echo/json",
success: function() {
callback(true);
},
error: function() {
callback(false);
}
});
http://jsfiddle.net/PK76X/152/
Callback is nothing but the value returned by a function.
When OP states callback, in the explanation of ans, he is referencing the address of return value.
For example: In var a = '10' a is the address and 10 is the value stored in it.
Now consider a function b() which returns some value:
function b(){
var a ='a';
return a;
}
var something = b(); // here **something** can be seen as callback of b()
Now coming to your point when OP uses the word callback in this code he is referring nothing but a variable. You can replace the word callback with any work like test, abc and it will still produce the same result.
Hope this helps
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
Sorry, but I am new to jQuery so this may seem like a dumb question.
I have a generic function that will call a $.get to retrieve some data from a URL and I then want to assign to a variable, not a control.
Here's my function, it has been simplified to clear out the "noise"...
function LoadFromURL(url) {
var response = "";
$("textarea#dump").val("url=" + url); // Shows the URL, no problem
$.get(url, "", function (data) {
response = data;
$("textarea#dump").val(response); // Shows the data, no problem
});
$("textarea#dump").val(response); // Shows NOTHING!
return (response);
}
The problem is that the response value quite happily assigns inside the callback function, but when it gets to the return (response) then the variable is empty.
The Shows NOTHING line is fired too soon to be useful. You must start from the callback function and go from there. You could call a method from the callback.
Call it like this:
var cb = function(data) {
$("textarea#dump").val(data);
}
LoadFromUrl("someUrl", cb);
or inline like this:
LoadFromUrl("someUrl", function(data) {
$("textarea#dump").val(data);
});
Change your method like this:
function LoadFromURL(url, cb) {
$("textarea#dump").val("url=" + url); // Shows the URL, no problem
$.get(url, "", function (data) {
cb(data); //<-- call the CallBack method
});
}
This is more the behavior of javascript than jQuery, callbacks are a way of life in js.