closures with ajax, using variable from ajax - javascript

I am having problems using variables inside functions. So I have code:
functions.js:
function foo (callback){
$.ajax({
type:"POST",
url:"ajax/companyInfo.php",
data: dataString,
success: callback
});//end ajax
alert (dada);
}
function mycallback (result){
array=result.split('/');
alert(dada);
}
invoice.php:
var array = [];
var dada="";
$('#next1').on('click', function(){
dataString='company= '+$(this).closest('.inside').find('select').val(); // this is just for ajax
resizeall($(this), 200, 100); //this is function that works and has no problem
foo(mycallback);
console.log(array);
});//end on click function
It says:
Uncaught ReferenceError: dada is not defined functions.js:41
Uncaught ReferenceError: dada is not defined functions.js:46
I think it's might be related to closures isn't it. What is going wrong?

Kind of hard to debug since I can't see all of the invoice.php or functions.js
The line numbers you report (41 and 46) indicate that there is more to functions.js then
what you pasted.
But I'll give a hack you could try
invoice.php
var array = [];
window.dada="";
$('#next1').on('click', function(){
dataString='company= '+$(this).closest('.inside').find('select').val(); // this is just for ajax
resizeall($(this), 200, 100); //this is function that works and has no problem
foo(mycallback);
console.log(array);
});//end on click function
functions.js
function foo (callback){
$.ajax({
type:"POST",
url:"ajax/companyInfo.php",
data: dataString,
success: callback
});//end ajax
alert (window.dada);
}
function mycallback (result){
array=result.split('/');
alert(window.dada);
}

Here is what your setup should look like.
function getCompanyInfo(companyName) {
return $.post("ajax/companyInfo.php", {
company: companyName
}).then(function (rawData) {
return rawData.split("/");
});
}
$('#next1').on('click', function() {
var companyName = $(this).closest('.inside').find('select').val();
resizeall($(this), 200, 100);
getCompanyInfo(companyName).done(function (array) {
console.log(array);
// everything else you want to do with the array goes here
});
});
Read up on jQuery Deferreds to find out what .then() and .done() do.
Final tip: If you want to update data on the server, use a POST request. If you want to fetch information from the server, use a GET request. The .post() in my code above is there because you used it in your code. It's semantically wrong and you really should change it to .get().

Related

How to Execute code after function is complete

I have a code where basically I've created a function in which, by the help of jQuery ajax, I fetch a value and set it as a data attribute of an element.
then after calling the function, I store the data value in a variable.
But the problem is that I don't want to execute any code before the ajax function completes.
JS
function load_data(){
$.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar')
}
})
}
load_data(); //let the function set data first
console.log($('.element').data('foo')) //then execute this line
How to achieve this?
You can receive a callback function in load_data and execute it in the success function. Something like this:
function load_data(callback){
$.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar');
callback();
}
})
}
load_data(function() {
console.log($('.element').data('foo'));
});
Of course, if this is your real scenario, you could simply put console.log($('.element').data('foo')); directly inside the success function.
You can use, Async-Await. https://javascript.info/async-await
async function load_data(){
await $.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar')
}
});
console.log($('.element').data('foo')) //then execute this line
}
load_data(); //let the function set data first
Also, you can do it using callback as well.
function load_data(callback){
$.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar');
callback();
}
})
}
function doItLater(){
console.log($('.element').data('foo')) //then execute this line
}
load_data(doItLater); //let the function set data first
You can pass the data as a parameter to doItLater for getting data to your current scope.
try using .done()
load_data()
.done(function(dataResponse){
console.log($('.element').data('foo')) //then execute this line
}); //let the function set data first
the code inside will run after a your ajax call is responded and dataResponse has any response from you ajax call
This is not directly possible due to Asynchronous ajax call.
There are two ways to achieve what you want
1.
Create a function/s for the code you want to execute after successful ajax request
Call that function/s from ajax success block
Eg.
function load_data(){
$.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar');
console.log($('.element').data('foo')); // Your code goes here
}
})
}
2
Return $.ajax in load_data function
And use .then or .done function for load_data itself
Eg.
function load_data(){
return $.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar')
}
})
}
load_data().done(function() {
console.log($('.element').data('foo')); // Your code goes here
});
However, .done and .then do not behave the same. In particular, if a standard promise callback returns another promise, this will delay the resolution of all later promises. jQuery's then behaves like this, but done does not. It is not possible for a done callback to delay the resolution of later callbacks.
Ajax is asynchronous. So, you have to listen for success event and do your stuff. You might achieve something similar to your needs by using await/async
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/async_function
const load_data = async () => {
return await fetch('https://exmaple.com');
}
load_data();
$('.element').attr('data-foo', 'bar')
You could just put the console log inside of the success callback, after you set the element attribute.
If you don't want the console log written inside load_data (maybe you want to make load_data reusable, without the console log), you could put the console log in a callback function and pass the callback to load_data and call it in the ajax success function:
function load_data(cb){
$.ajax({
.....,
success: function (response) {
$('.element').attr('data-foo', 'bar')
cb();
}
})
}
function callback() {
console.log($('.element').data('foo'))
}
load_data(callback);
Another option is to set async: false in the ajax settings object, which would prevent following code from being executed before the ajax function resolves, but this is not generally a recommended practice.
with this:
$.when(load_data()).then(console.log($('.element').data('foo')));

Variable scope with deferred / ajax in jQuery

I'm using pretty standard setup I think. A click on element to call a function that handles an ajax request.
My limited understanding of variable scope and callbacks when using asynchronous anything and trying to figure out jQuery deferreds is making my feeble brain hurt.
$('<div>')
.on({
click : function(){
console.log(
fetchMyData() // this will be 'undefined' but why?
)
}
})
function fetchMyData(){
$.ajax({
// ajax setup
})
.done(function(response){
console.log( response ); // shows 'hello' as expected
return response;
})
}
I get that the ajax call will not necessarily be done by the time I'm doing the console.log(), since it's asynchronous of course.
So how can I make it such that fetchMyData() will display the ajax result once it's ready?
You should change what fetchMyData function does. Try returning the promise object.
$('<div>').click(function()
{
var fetchMyDataPromise = fetchMyData() ;
fetchMyDataPromise.done(function(response)
{
console.log(response);
});
});
function fetchMyData()
{
return $.ajax({ // ajax setup });
}
You can use jQuery When like this :
$('<div>')
.on({
click : function() {
$.when(fetchMyData()).then(function(data) {
console.log(data);
});
}
});
function fetchMyData(){
return $.ajax({
// ajax setup
});
}
So how can I make it such that fetchMyData() will display the ajax result once it's ready?
You've already done that, in the .done callback. If you want fetchMyData to return the response, you have to use a synchronous call, which is usually not the right thing to do (because the UI will freeze until the response arrives).
Maybe you want to modify your function to take a callback:
function fetchMyData(thenDoThis){
$.ajax({
// ajax setup
}).done(thenDoThis)
}
function doSomethingWithResponse(response) {
// do something
}
Then call it like this:
fetchMyData(doSomethingWithResponse);
Or like this:
$('<div>').click(function() {
fetchMyData(function(response){
console.log(response);
});
});

Getting caller name during ajaxSend or ajaxSuccess

I want to extend all of my application's ajax calls with some special case handlers and be able to refire the method that started the ajax call if I need to. The problem I am having is I cannot get the name of the calling function that triggered the ajax call from my anonymous function event handlers, either ajaxSend or ajaxSuccess. I have tried all of the variations of caller/callee that are commented below plus many others. Here is some sample code:
var ajaxcaller;
$(document).ajaxSend(function(event,xhr,settings){
// Before we fire off our call lets store the caller.
// ajaxcaller = arguments.callee.caller.name;
//alert("get caller:"+arguments.callee.caller.name);
//alert("get caller:"+caller.name);
//alert("get caller:"+this.caller.toString());
//alert("get caller:"+event.caller.toString());
});
$(document).ajaxSuccess(function(event,xhr,settings){
var xobj = $.parseJSON(request.responseText);
if(xobj.ReFire === 1){
//Successful ajax call but not results we expected, let's refire
//Fix some params automagically here then
//SOME CODE HERE THAT Refires my caller
}
});
$(document).ajaxError(function(event,xhr,settings){
var xobj = $.parseJSON(request.responseText);
if(xobj.ReFire === 1){
//Fix some params automagically here then
//SOME CODE HERE THAT Refires my caller
}
});
Here's an idea, however I am not sure how reliable it would be, but you could intercept jQuery.ajax calls and append a caller property to the options that would reference the calling function as well as an args property that would reference the arguments that were passed to that function.
I am sure that if you play around with that idea, you will find a solution to your problem. If you don't like the idea of overriding jQuery.ajax, you could simply make sure to pass those references as options in all your ajax calls.
DEMO: http://jsfiddle.net/zVsk2/
jQuery.ajax = (function (fn) {
return function (options) {
var caller = arguments.callee.caller;
options.caller = caller;
options.args = caller.arguments;
return fn.apply(this, arguments);
};
})(jQuery.ajax);
$(document).ajaxSend(function (e, xhr, options) {
console.log('caller', options.caller);
console.log('args', options.args);
});
function getRecords(someArgument) {
return $.ajax({
url: '/echo/json/',
dataType: 'json',
data: {
json: JSON.stringify({ test: someArgument})
}
});
}
getRecords(1);
getRecords(2);

jquery execute function when two conditions are met

I need to execute a specific function mvFinishItUp() when two conditions are met. More specifically, one condition is the callback success of a $.ajax the other is a normal flow of the code until it reaches the function. Kinda of this:
$.ajax({
url: mv_finalUrl,
success: function (data) {
mvFinishItUp(data);
},
dataType: 'html'
});
/* here a lot more code, with animations and some delays */
mvFinishItUp(data) {
/* My function code */
/* But this code must only run after it has been called via the call back
and after all the other code has been ran as well */
}
So, the function must wait for all the code if the ajax callback is quicker, or the other way around. Any ideas on how this could be implemented?
I'm willing to change the whole concept of script code, as I believe the loose code between the ajax, and the function itself should go to a function aswell ...
This is a perfect use case for jQuery Deferred objects.
Remove the success: parameter from the AJAX call, and register the handler later:
var jqxhr = $.ajax(...);
// do some other synchronous stuff
...
// and *then* register the callback
jqxhr.done(mvFinishItUp);
Deferred objects cope perfectly well (by design) with being registered on an AJAX event after that event already finished.
Try like below, (It is just psuedo code)
var isAJAXDone = false, isFunctionCodeDone = false;
$.ajax({
//..
success: function () {
isAJAXDone = true;
mvFinishItUp(data, isAJAXDone, isFunctionCodeDone);
}
});
//..Your function code
//..Add this below the last line before the function ends
isFunctionCodeDone = true;
mvFinishItUp(data, isAJAXDone, isFunctionCodeDone);
//..
mvFinishItUp(data, isAJAXDone, isFunctionCodeDone ) {
if (isAJAXDone && isFunctionCodeDone) {
//Do your magic
}
}
Maybe something like this would do the trick:
var _data = undefined;
$.ajax({
url: mv_finalUrl,
success: function (data) {
_data = data;
myFinishItUp(data); // call the function from here if it's faster
},
dataType: 'html'
});
/* here a lot more code, with animations and some delays */
function myFinishItUp(data) {
this.data = data; // store the data from the AJAX call or the code, whichever reaches first
// if the code reaches this before the AJAX call completes, data will be undefined
if(typeof this.wasCalled == "undefined") {
/* My function code */
/* But this code must only run after it has been called via the call back
and after all the other code has been ran as well */
this.wasCalled = true;
}
}(_data); // function that calls itself when the code gets to this point with a self-contained boolean variable to keep track of whether it has already been called
I used a self calling function execute when the code flow gets to that point, but if it's called from the AJAX call, it won't execute. It keeps track of whether or not it's already been called with a self-contained boolean value.
Here I add an second parameter to check callback check
function mvFinishItUp(data, byCallback) {
var iscallback = byCallback || false; // if you don't send byCallback
// default will false
if(iscallback) {
// execute if called by callback
}
}
success: function (data) {
mvFinishItUp(data, true); // call with second parameter true
},
To execute mvFinishItUp() after ajax done and all codes between ajax and mvFinishItUp finished you can do something like this:
var allFunctionExecuted = false; // global to detect all code execution
$.ajax({
url: mv_finalUrl,
success: function (data) {
mvFinishItUp(data, true);
},
dataType: 'html'
});
function func1() {
}
function func2() {
}
// some other code
function func3() {
allFunctionExecuted = true;
}
Now,
function mvFinishItUp(data, byCallback) {
var iscallback = byCallback || false; // if you don't send byCallback
// default will false
if(iscallback && allFunctionExecuted) {
// execute if ajax done
// and others code done
}
}
This is very "ugly" code, but you can modify it to not use global vars, so this is just illustrative:
var ajaxExecuted = false,
codeExecuted = false;
$.ajax({
url: mv_finalUrl,
success: function (data) {
ajaxExecuted = true;
mvFinishItUp(data);
},
dataType: 'html'
});
/* here a lot more code, with animations and some delays */
codeExecuted = true;
mvFinishItUp(data) {
/* My function code */
if(ajaxExecuted && codeExecuted) {
/* But this code must only run after it has been called via the call back
and after all the other code has been ran as well */
}
}
I just added two flags: ajaxExecuted and codeExecuted, and inside the function an if statement that checks the value of the those flags, and executes only when the two of them are set to true. So no mather who calls it first, it get only executed when the two flags are set to true.
A cleaner way could be to implement the function in an object, and use properties instead of global vars.

Still Having Problems Returning Value Through Function

I'm having serious problems with the function below:
function requestUploadedSearch()
{
var cookie = JSON.parse(readCookie("user_search_cookie"));
$.ajax({
dataType: "script",
async: false,
data: {
context: "search-get",
code: removeNull(cookie, cookie !== null, "code")
},
success: function(data)
{
var keywords = search_return["keywords"];
return keywords; // here is the damn problem.
}
});
}
Seams that simply nothing comes out of the function except for the undefined value and no errors are shown in the debugger.
And I'm seriously almost throwing my laptop on the wall.
If anyone could help me doing this, please answer!
Thanks in advance.
1st off: Where is the search_return variable? Why are you ignoring data?
I have a feeling this is what you want to do:
function requestUploadedSearch()
{
var cookie = JSON.parse(readCookie("user_search_cookie"));
var keywords;
$.ajax({
dataType: "json",
async: false,
data: {
context: "search-get",
code: removeNull(cookie, cookie !== null, "code")
},
success: function(data)
{
keywords = data["keywords"];
}
});
return keywords;
}
The issue is that since the Ajax call will complete at an arbitrary time in the future, you cannot simply return a value from its success handler.
One issue is that you're not actually doing anything with the data returned by the server, which seems puzzling.
The nutshell version is that you need to implement the functionality as part of the success callback. That can be done in-line, or you can create the callback function outside of the Ajax call itself and use it as the value for the success property:
function onSuccess(data) {
// Do something with the data here
}
...
$.ajax({ // etc.
success: onSuccess
};
You may also use jQuery's $.when function.
The problem is the scope you're trying to return your keywords from. The success function is called by jQuery, and you don't have any control over what jQuery does with that return value. You could do return $.ajax(... but you wouldn't get what you expect, since according to the documentation: "As of jQuery 1.5, the $.ajax() method returns the jqXHR object, which is a superset of the XMLHTTPRequest object" (http://api.jquery.com/Types/#jqXHR).
What you should do instead is set up a callback function like:
function doSomethingWithKeywords(keywords) {
// do stuff
};
and in the success function call that function:
doSomethingWithKeywords(keywords);
EDIT: Hogan's is a good solution, since your call isn't asynchronous.
The problem you are having is the return you are passing is not the return of the function -- it is the return of the event of success. Often closures (implied passing of a local variable to a function) are used to solve this problem in JavaScript.
NB I still don't think your function will work because I don't see where search_return["keywords"] is defined. But at least you won't have to worry about the closure issue. Once your success function is correct the main function will return it.
Like this:
function requestUploadedSearch()
{
var cookie = JSON.parse(readCookie("user_search_cookie"));
var returnClosure;
$.ajax({
dataType: "script",
async: false,
data: {
context: "search-get",
code: removeNull(cookie, cookie !== null, "code")
},
success: function(data)
{
// returnClosure = data["keywords"];
returnClosure = search_return["keywords"];
}
});
return returnClosure;
}

Categories

Resources