I have a function containing an ajax call:
function example(param, callback) {
$.ajax({
type: "GET",
url: param,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function(data) {
// do something with data
callback(data);
}
});
}
I call it by:
example("http://www.example.com", function(result) {
// do something with result
})
But, I'd like to use example() in this context:
text.replace(/[regex not shown]/g, function(){
return RegExp.$1 + example(RegExp.$2); // does not work
});
i.e., the regex finds multiple matches, to which I then add example([whatever it matched]). Is there a way to integrate
example("http://www.example.com", function(result) {
// do something with result
})
into the text.replace()?
Thank you in advance!
You can't. That's because you are passing a to the .replace() method a function literal, so the replace method will take that function .toString() returned string (its source code) as an argument.
That is because .replace() method is synchronous and don't expect a callback as second argument, but a string, so it will convert any second argument to string if is not.
And if you actually call the function in the parameter, cause your function has no defined return value will parse "undefined" as second value.
But you can write your own asynchronous replace method and add it to the String prototype. I can't edit code in my phone, so when I get back to my computer I write it for you if you haven't figured out.
Edit:
Actually I was wrong, you can use a callback in the replace method. The problem is the way you are using an asynchronous call inside there. I don't know what are you exactly trying to do, so I hope this help you.
String.prototype.myReplace=function(re, o, p){
var v=[];
var t=this;
t.toString().replace(re, function(m){
if(m==RegExp.$1){v[1]=m;};
if(m==RegExp.$2){v[2]=m;};
});
$.ajax({
type: "GET",
url: v[2],
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function(data) {
// do something with data
o[p]=t.toString().replace(re, function(m){
if(m==RegExp.$1){return v[1];};
if(m==RegExp.$2){return data.toString();};
});
}
});
};
And call it like this:
text.myReplace(/[regex not shown]/g, this/* or whatever object is */, 'text'});
Create a function to make the ajax call and handle the replacement of matches on a regular expression. Based on what you supplied above, this is the most modular approach assuming you want to perform these types of replacements more than once.
function replaceTextAfterAjax(str, regex, matchSendToServer, fn) {
var matches = regex.exec(str);
var externUrl = matches[matchSendToServer];
$.ajax({
type: "GET",
url: externUrl,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function(json) {
fn(json.serverSideReplaceText, matches);
},
})
}
var text = "go to http://www.example.com";
replaceTextAfterAjax(text, /(go to) (.*)$/, 2, function(response, matches) {
text = matches[1] + ' ' + response;
// continue to use `text`
});
Notice that you should be keeping your use of RegExp local by invoking exec on the regular expression instance. This keeps your code thread-safe and prevents other methods from getting another call's RegExp.$N value.
friend, I don't understand your question clearly... you can try this below code... not sure will it work or not...
function example(param, callback) {
$.ajax({
type: "GET",
url: param,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
success: function(data) {
// do something with data
if(typeof callback!='undefined'){callback(data)}else{return data};
}
});
}
Try ConversationJS:
https://github.com/rhyneandrew/Conversation.JS
It allows you to make function calls in an entirely new way, essentially binding calls to events rather than making explicit calls. It would allow you to do exactly what you are trying to do in a much more "decoupled" manner, which means that it will also be easy to change and maintain in the future! Remember, nested dependencies are never good!
Related
I currently have the following (simplified here) code to action two Ajax calls which I need to complete before processing more code using a when (I know this could be chained but the when construct is expandable).
function f1(ID) {
return $.ajax({
url: "'/ajax/getF1/')?>" + '/' + ID,
dataType: "json"
});
}
function f2(ID) {
return $.ajax({
url: "'/ajax/getF2/')?>" + '/' + ID,
dataType: "json"
});
}
$.when(
f1(ID),
f2(ID)
).done(function(a1,a2) {
....do something...
});
This seems inelegant, so my question is how do I turn the two named function f1 and f2 into anonymous functions called inline. Simply substituting (say) f1 with the contents of the f1 function doesn't work.
It seems to me that this should be simple, but it's eluding me.
You pass promises to $.when() not functions. So, what you could do is this:
$.when($.ajax(...), $.ajax(...)).then(...)
There is no need for an intermediate function.
Just do:
$.when(
$.ajax({
url: "'/ajax/getF1/')?>" + '/' + ID,
dataType: "json"
}),
$.ajax({
url: "'/ajax/getF2/')?>" + '/' + ID,
dataType: "json"
})
).done(function(a1,a2) {
....do something...
})
I usually like to organize my code so that one function fires a bunch of other
functions, like this:
/**
* GET MESSAGES:
*/
$(function() {
$.ajax({
url: '/messages',
method: 'GET',
dataType: 'json',
success: function(messages) {
if (messages.length > 0) {
keyedMessages = keyFork(messages);
reversedMessages = reverse(keyedMessages);
crushedMessages = crush(reversedMessages);
getFriendships(messages, crushedMessages);
}
mail.template.airmail();
}
});
});
However, if I need to do a second Ajax request inside one of the nested
functions I can't return the data because of the scope of the Ajax request
and it makes my code inconsistent and hard to follow, sort of broken up all over the place. For example, if one of the functions
invoked above fires a second Ajax request for friendships anything I write
after that will be broken from the communication chain due to the request and it seems impossible to return anything:
/**
* GET FRIENDSHIPS:
*/
function getFriendships(messages, crushedMessages) {
$.ajax({
url: 'friendships',
method: 'get',
dataType: 'json',
success: function(friendships) {
addKey(crushedMessages, friendships);
filteredCrushedMessages = filterUnconfirmedSender(crushedMessages);
filteredCrushedMessages.forEach(function(filteredCrushedMessage) {
mail.sidebar.builder.messengers(filteredCrushedMessage);
});
mail.snailMail.onload();
}
});
}
If I try to return the data it doesn't work. Consequently I'll have to
continue invoking functions inside the nested request, every time I need to make another nested ajax request it breaks the chain. This makes my
code very hard to read. Are there any solutions to this problem or is
code that uses Ajax requests just hard to read?
You could store the data on a DOM element, then use jQuery Custom Events to get it done.
There's even support for passing arguments to your event handler:
https://learn.jquery.com/events/introduction-to-custom-events/#naming-custom-events
If I try to return the data it doesn't work.
Not appear jQuery promise returned from either function at Question ?
Try utilizing return statement , $.when.apply(this, arrayOfPromises) to return array of jQuery promise object from getFriendships
function getFriendships(messages, crushedMessages) {
return $.ajax({
url: 'friendships',
method: 'get',
dataType: 'json',
success: function(friendships) {
addKey(crushedMessages, friendships);
filteredCrushedMessages = filterUnconfirmedSender(crushedMessages);
mail.snailMail.onload();
return $.when.apply($
, filteredCrushedMessages.map(function(filteredCrushedMessage) {
return mail.sidebar.builder.messengers(filteredCrushedMessage);
})
);
}
});
}
// e.g.,
getFriendships(messages, crushedMessages)
.then(function success() {
console.log(arguments)
}, function err(jqxhr, textStatus, errorThrown) {
console.log(errorThrown)
})
Method for handling ajax
function ajaxMethod(){
return $.ajax({
url: ajaxUrl,
type: "POST",
dataType: "JSONP",
jsonpCallback: ajaxCallback
});
}
Calls to this method:
dD(ajaxMethod());
aA(ajaxMethod());
bB(ajaxMethod());
cC(ajaxMethod());
aa,bb,cc,dd method have
promise.success(function (response) {
console.log(response);
});
Now aA response is coming in bB function,,bb response in cc function and as simultaneous call is coming.
Also tried using async true nothing happens.
Any suggestions?
With jsonpCallback you are telling jQuery to use a specific function name for the callback function (instead of generating a unique one), so each time you call it, you overwrite the previous function.
Just remove jsonpCallback: ajaxCallback.
While you are at it, remove type: "POST",, it is incompatible with JSONP.
I think this is what you are after.
This code is using the returned promise to wait for the result then passing the result to your other function.
ajaxMethod().success(function(response)
{
dD(response);
});
ajaxMethod().success(function(response)
{
aA(response);
});
ajaxMethod().success(function(response)
{
cC(response);
});
ajaxMethod().success(function(response)
{
dD(response);
});
Your aA, bB, cC and dD methods can now be:
function <insertname>(response)
{
console.log(response);
}
If you want your request to come in the synchronous way, then try the following :
var callBack = $.Callbacks();
callBack.add(dD(ajaxMethod()));
callBack.add(aA(ajaxMethod()));
callBack.add(bB(ajaxMethod()));
callBack.add(cC(ajaxMethod()));
callBack.fire();
the above line of code will make sure the respective ajax call would get call.
so this is my setup: I am calling a .each on a number of elements and after a few checks I send an ajax request with some JSON data and on success I apply the server response as an attribute to each element(it is usually an id). After that I push the id to an array.
The problem is that obviously ajax requests are asynchronous and the function that uses the array of element ids fires before all ajax have had time to finish.
I've tried with .when and .then but the callback function keeps getting fired way ahead of the ajax.
Here is how my code looks( I've removed some unnecessary parts):
var order = [];
function sub(selector){
selector.each(function(){
var out = {
"some":"random",
"stuff":"here"
};
$.ajax({
type: "POST"
url: "/test/url",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data:JSON.stringify(out),
success:function(response){
$(this).attr("data-response",response);
order.push(response);
}
})
})
}
$("#button").click(function(){
$.when(sub($(".test"))).then(function() {
console.log(order);
//i have to run the sub function twice so the order doesn't return undefined
});
});
The problem is that when acts on deferred objects, however sub doesn't return anything so when fires right away. So what you need to do is to collect all the deferred objects returned by the ajax calls and return them:
var order = [];
function sub(selector){
var deferredList = []
selector.each(function(){
var out = {
"some":"random",
"stuff":"here"
};
var deferred = $.ajax({
type: "POST",
url: "/test/url",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data:JSON.stringify(out),
success:function(response){
$(this).attr("data-response",response);
order.push(response);
}
})
deferredList.push(deferred)
})
return deferredList;
}
$("#button").click(function(){
$.when.apply($,sub($(".test"))).then(function() {
console.log(order);
//i have to run the sub function twice so the order doesn't return undefined
});
});
The reason to use apply and not when directly is that when doesn't accept array of objects as a parameter and apply provides us the work-around for this.
The argument to $.when() should be a Deferred, but sub() doesn't return anything. This version returns an array of all the Deferreds returned by $.ajax, and calls $.when with them all as arguments; it will then wait for all of them.
var order = [];
function sub(selector){
return selector.map(function(){
var out = {
"some":"random",
"stuff":"here"
};
return $.ajax({
type: "POST"
url: "/test/url",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data:JSON.stringify(out),
success:function(response){
$(this).attr("data-response",response);
order.push(response);
}
})
})
}
$("#button").click(function(){
$.when.apply(this, sub($(".test"))).then(function() {
console.log(order);
//i have to run the sub function twice so the order doesn't return undefined
});
});
Your approach produces a whole lot of more server requests and will scale terribly. Since you want to wait for all results anyway, a much better solution would be to collect all data and send only one ajax request which returns an array of results for each data object.
Using a deferred object (as seen in other answers) then gives you the ability to use that result in a when statement.
try to use a callback-function in success:
var order = [];
function sub(selector, callback){
selector.each(function(){
var out = {
"some":"random",
"stuff":"here"
};
$.ajax({
type: "POST"
url: "/test/url",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data:JSON.stringify(out),
success:function(response){
$(this).attr("data-response",response);
order.push(response);
callback();
}
})
})
}
$("#button").click(function(){
sub($(".test"), function() { console.log(order) });
});
Add attribute async : false to your $.ajax - call. Then the calls are made in sequence after eachother.
I'm experimenting with MCV using jquery. I'm making a call to an api, which returns data - what I want to do is return the data to a variable rather than call an additioanl function within my model. The following code doesn't do what I wish though (the_data = result). Any ideas how I can achieve this?
function lookForSomething()
{
var the_data = $.ajax({ type: "GET",
url: TheUrl,
dataType: "jsonp",
success: function(result) { return result; }
});
return the_data;
}
Many thanks,
J
If understand you correctly, you want the data returned by TheUrl to be the return value of the lookForSomething.
Technically, you could do this, with the async option:
function lookForSomething()
{
var the_data;
$.ajax({ type: "GET",
url: TheUrl,
dataType: "jsonp",
async : false,
success: function(result) { the_data = result; }
});
return the_data;
}
I strongly urge you not to do this. It's un-Javascript-like and it will lock up the user's browser while it's running. Much better to pass in a callback to the function and invoke it from success.
You are probably looking for deferred objects:
function lookForSomething()
{
var the_data;
$.when(
$.ajax({ type: "GET",
url: TheUrl,
dataType: "jsonp",
success: function(result) { the_data=result; }
});
).done(function() {
return the_data;
}).fail(function() {
return '';
});
}
Keep in mind that this is still asynchronous, so when you make a call for var ddd = lookForSomething();, ddd will not have the value you expect since the call may still be running. The only reason I brought up $.when() is because it seems like you require a lot of dependencies. $.when() allows you to wait for multiple ajax commands.