Javascript When and Done Function use - javascript

I am trying to call two different functions in third function but one after the other.One function has ajax call, whose values are used in other function. it is step by step process. I don't want to use one into the other.
function f1()
{
// ajax call
return r1
}
function f2(r2)
{
// do some of the work based on r2
}
function f3()
{
$.when(f1()).done(function(data){
f2(data)
});
}
I also tried with $.when().then(); but still of no use.
Thanks, in advance.
UPDATE :- Below is the answer for my Question based on solution provide by #dreamweiver.
var json_data = '';
function f1()
{
$.ajax({
url: "test.php",
method: "POST",
async : false,
data: { },
success:function(data){
json_data = eval(data);
}
});
}
function f2(t)
{
console.log("values is "+t);
}
function f3()
{
$.when(f1()).done(function(){
f2(json_data);
});
}
Thanks everyone for your feedbacks.

Try this way, I have tested locally and it works perfectly
function deferredCalls () {
var jsonData = '';
var f1 = function ()
{
// ajax call
$.ajax({
url: "test.html",
method: "POST",
data: { id : menuId }
}).done(function(data) {
jsonData = data; //set the data
});
}
var f2 = function (data)
{
// do some of the work based on data
if(!!data){
//process the data
}
}
$.when(f1).done(function(){
f2(jsonData);
});
}
f1 function is called first which would in turn make a ajax request and return data on success, which is set to a function scope variable jsonData. Once this process is completed, f2 would be called which will start using jsonData, which is nothing but the data received from f1 function call.

This should be working:
function f1() {
// Or some other Ajax request that returns a promise
return $.getJSON('path/to/your/service');
}
function f2(r2) {
// ...
}
f1().done(f2);

Related

return AJAX inside AJAX call

I want to return the second ajaxcall as result of the ajax function, can anyone help me.
private ajax(url: string, method:string, data:any = null) {
var _this = this;
return this.csrfWithoutDone().done(function (res) {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': res
}
});
return $.ajax({
url: _this.baseUrl + url,
type: method,
data: data,
});
});
}
the csrfWithoutDone function:
return $.ajax({
url: _this.baseUrl + '/api/csrf',
type: 'GET'
});
BTW: this is writen in typescript but if you replace private with function and remove the : (type) it works in js too.
What you should do is CHAIN the calls.
The .done() function is asynchronous. Therefore it will execute whatever you pass it as an argument when the response is back. That function's returned value goes nowhere.
What you should do instead is:
foo.then(function() { /*step 1 /}).then(function({ / step 2 */ })
I would suggest reading a little bit about asynchrounousity in Javascript.
This is the way you would do it with promises, I have never worked with jQuery so the syntax might differ.
edit: I would add that there is no way to return the response value in your initial function. the best you can do is return the jqXHR object, And then call the "then()" or "done()" from the caller.
You should return a Promised object in your ajax function, to be able to find out if your request is done or not. Since you are using jQuery, you can use Deferred Objects:
function ajax(url, method, data) {
var _this = this;
// Create a deferred object
var dfd = $.Deferred();
this.csrfWithoutDone().done(function (res) {
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': res
}
});
$.ajax({
url: _this.baseUrl + url,
type: method,
data: data,
}).done(function (response) {
// your inner ajax has been done
// tell your promised object and pass the response to it
dfd.resolve(response);
});
});
// return promised
return dfd.promise();
}
// call your ajax function, it is a promised object
var ajaxRequest = ajax();
// so you can wait for the response
ajaxRequest.done(function (response) {
// your ajax has been done and you have the response
console.log(response);
});
I've implemented a simple code to find out how Promised object works:
function ajax() {
var dfd = $.Deferred();
setTimeout(function () {
dfd.resolve('Hello World');
}, 1000);
return dfd.promise();
}
var testResult = ajax();
testResult.done(function (response) {
alert(response);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can use native Promise Object as well, and maybe you need polyfill, to support all browsers, see Can I Use.

make a real ajax call with jasmine

I want to use Jasmine for two things, test a function that does a real ajax call, and acquire the callback data from the ajax call for use in additional jasmine tests.
This is what I have so far:
Javascript function:
function getAttributeInfo(selectedLayer){
// Get layer attributes
$.ajax({
type: 'get',
url: '/geoserver/oqplatform/ows?service=WFS&version=1.0.0&request=GetFeature&typeName='+ selectedLayer +'&outputFormat=json',
success: function(data) {
// pass the data into a global variable
foo = data;
// EDIT
return data;
}
});
}
The test:
it("an ajax test", function() {
var ajaxFunction = getAttributeInfo(SVIRLayerNames[0]);
// creating spied callback
var callback = jasmine.createSpy('callback');
spyOn($, 'ajax').and.callFake(function (req) {
var d = $.Deferred();
return d.promise();
});
// EDIT
//ajaxFunction.fetch(callback);
ajaxFunction(callback);
// everything after this does not seem to execute
var fakeData = callback.calls.mostRecent().args[0];
});
If I console log the foo variable after 5 seconds I can see that the ajax request was made and the data is available in the foo variable
After a few days looking into this, my big take away is that Jasmine is a great tool, but the documentation is terrible. I found it very difficult to simply understand what a spy is and when a it should be used.
My solution was to not use a spy at all.
beforeAll(function(done) {
var mySyncFunction = function () {
var layerName = 'foobar';
var layerRequest = getAttributeInfo(layerName);
layerRequest.success(function(layerResponse) {
// Pass data from the response into a global variable to be tests
// I can also check for things like the API version number.
});
layerRequest.done(function() {
// Alert Jasmine that the AJAX call is done
done();
});
};
mySyncFunction();
}
And in the getAttributeInfo function I added return just before $.ajax
UPDATE
...
beforeAll(function(done) {
$.ajax({
url: '/my/data',
data: {},
success: function (response) {
foo = response
done();
},
dataType: 'html'
});
});
////////////////
// Some tests //
////////////////
it("meets some requirement", function() {
for (var i = 0; i < foo.length; i++) {
var name = foo[i].fields.name;
expect(name).toBeDefined();
}
});

Trying to understand function and callback scope by filling out objects

I have make some functions to retrieve data using the Github API. I have the callbacks in place to get the data but I am sure how to understand where a function exits and when I stops modifying things.
For example in the code below, in the first function, when the AJAX call is successful, the callback is executed in the second function where the data is manipulated. Does that mean the the return in the first function is not needed or used? And in the second function is the data used and pushed to the array and then the array returned or is it the other way around where the (empty) array is returned and then the callback does its thing.
I am ultimately trying to get the data from the callback into an object and return that filled object from the parent function.
function makeAJAXCall(hash, cb) {
var returnedJSON, cb = cb, hash = hash;
$.ajax({
accepts: 'application/vnd.github-blob.raw',
dataType: 'jsonp',
url: hash,
success: function (json) {
console.info(json);
returnedJSON = json;
// Time for callback to be executed
if (cb) {
cb(json);
}
},
error: function (error) {
console.error(error);
// an error happened, check it out.
throw error;
}
});
return returnedJSON;
}
function parseBlob(hash) {
var objectedJSON, objectList = [], i;
objectedJSON = makeAJAXCall(hash, function (objectedJSON) { // no loop as only one entry
objectList.push(objectedJSON.content);
});
return objectList;
}
function walkTree(hash) {
var objectedJSON, objectList = [], i, entry;
var hash = 'https://api.github.com/repos/myAccountName/repo/git/trees/' + hash;
objectedJSON = makeAJAXCall(hash, function (objectedJSON) {
for (i = 0; i < objectedJSON.data.tree.length; i += 1) {
entry = objectedJSON.data.tree[i];
console.debug(entry);
if (entry.type === 'blob') {
if (entry.path.slice(-4) === '.svg') { // we only want the svg images not the ignore file and README etc
console.info(entry.path)
objectList.push(parseBlob(entry.url));
}
} else if (entry.type === 'tree') {
objectList.push(walkTree(entry.sha));
}
}
});
console.info(objectList);
return objectList;
}
$(document).ready(function () {
var objects = walkTree('master', function () { // master to start at the top and work our way down
console.info(objects);
});
});
Here you are making an AJAX call A refers to asynchronous, ie your success/error callback will be executed asynchronously.
makeAJAXCall will return before executing success/error of $ajax.
so the objectedJSON = makeAJAXCall will return you undefined
function makeAJAXCall(hash, cb) {
$.ajax({
accepts: 'application/vnd.github-blob.raw',
dataType: 'jsonp',
url: hash,
success: function (json) {
// this function will be executed after getting response from server
//ie Asynchronously
//here cb passed from the makeAjaxCall exist in the closure scope
if (cb) {
cb(json);
}
},
error: function (error) {
console.error(error);
// an error happened, check it out.
throw error;
}
});
}
Now when you call makeAjaxCall the callback function you are passing will exist in the closure scope of $.ajax and will be executed on success of server response
makeAJAXCall(hash, function (objectedJSON) {
//objectJSON contains the response from server
// do all your operations using server response over here or assign it to a global variable
});
check below links
https://developer.mozilla.org/en/JavaScript/Guide/Closures
https://mikewest.org/2009/05/asynchronous-execution-javascript-and-you
or you can make your ajax call in sync using async:false which is highly not recommended
function makeAJAXCall(hash, cb) {
var returnedJSON;
$.ajax({
accepts: 'application/vnd.github-blob.raw',
dataType: 'json',
async : false, //this will make it in sync
url: hash,
success: function (json) {
console.info(json);
returnedJSON = json;
//now makeAJAXCall will wait for success to complete and it will return only after executing success/error
// Time for callback to be executed
if (cb) {
cb(json);
}
},
error: function (error) {
console.error(error);
// an error happened, check it out.
throw error;
}
});
//will wait for success/error before returning
return returnedJSON;
}
In the above case your code will work
function makeAJAXCall(hash, cb) {
var returnedJSON, cb = cb, hash = hash;
return $.ajax({
accepts: 'application/vnd.github-blob.raw',
dataType: 'jsonp',
url: hash,
success: function (json) {
console.info(json);
returnedJSON = json;
// Time for callback to be executed
if (cb) {
cb(json);
}
},
error: function (error) {
console.error(error);
// an error happened, check it out.
throw error;
}
});
}
function parseBlob(hash) {
var objectedJSON, objectList = [], i;
objectedJSON = makeAJAXCall(hash, function (objectedJSON) { // no loop as only one entry
objectList.push(objectedJSON.content);
});
return objectList;
}
function walkTree(hash) {
var objectedJSON, objectList = [], i, entry;
var hash = 'https://api.github.com/repos/myAccountName/repo/git/trees/' + hash;
objectedJSON = $.when(maxAJAXCall)
.then(function(){
//Write the callback
});
Use $.when().then() to call ajax and manage the callbacks better.
.When

sequential function call, while one of them uses setTimeout

I want to call three functions someTask1, someTask2 and someTask3 in that order. However, the function someTask2 involves Ajax call, and keep calling itself recursively using setTimeout unless a desired value is return. The code looks like this:
doListOfTasks: function(myparam){
var someObj = someTask1(myParam);
someTask2(someObj);
someTask3(someObj);
},
someTask2: function(someObj){
$.ajax({
url: "someUrl.do",
type: "POST",
data: ({"id": rowObject.instanceId}),
dataType: "json",
async:false,
success: function(res){
if(res.prop1 != 'desired'){
setTimeout(function(){someTask2(someObj);}, 2000);
}
}
}
);
},
As you might have guessed, the execution of this code does not wait for someTask2 to return before calling someTask3.
I want the code inside doListOfTasks to be executed sequentially. How can I do that?
Also, I do not want to hard-code someTask3 in success callback. E.g. I do not want to do this:
success: function(res){
if(res.prop1 != 'desired'){
setTimeout(function(){someTask2(someObj);}, 2000);
}else{
someTask3(someObj);
}
}
How can achieve this?
Thanks
Edit#1
The problem is not being able to call the functions... but the problem is synchronization. I want someTask2 to finish whatever it's doing, and only then someTask3 is called.
someTask2 calls itself repetitively using setTimeout... I guess this triggers a new thread and someTask2 is returned after first call... triggering someTask3 in main thread. However, separate thread spawns (and gets killed) in each call setTimeout until the desired criteria is met.
That's why, while the someTask2 still looping, the call to someTask3 triggers.
Not sure how correct I am.
You can achieve this using a Deferred in jquery:
$.when(someTask1(), someTask2(), someTask3()).then(successFunc, errorFunc);
You need to return a custom made .Deferred object with a promise value.
someTask2: function(someObj)
{
var def = $.Deferred();
$.ajax({
url: "someUrl.do",
type: "POST",
data: ({"id": rowObject.instanceId}),
dataType: "json",
async:false,
success: function(res){
if(res.prop1 != 'desired'){
setTimeout(function(){someTask2(someObj);}, 2000);
}
else
{
def.resolve(res);
}
}
}
);
return def.promise();
}
So for example:
function someTask1()
{
var def = $.Deferred();
def.resolve('i\'m data resolved from task1');
return def.promise();
}
function someTask2(someObj)
{
var def = $.Deferred();
var count = 0;
var f = function() {
console.log(++count);
if (count > 2) {
def.resolve('whoop we got the value we wanted in task 2 after many tries: ' + count);
}
else
setTimeout(f, 1000);
};
f();
return def.promise();
}
function someTask3()
{
var def = $.Deferred();
def.resolve('and hello from task3!');
return def.promise();
}
var success = function(x) {
console.log('success:', arguments);
};
var error = function() {
console.log('oh no an error occured in one of the tasks.');
};
$.when(someTask1(), someTask2(), someTask3()).then(success , error);
Will show
1
2
3
success: ["i'm data resolved from task1",
"whoop we got the value ...k 2 after many tries: 3",
"and hello from task3!"]
fiddle available: http://jsfiddle.net/garreh/29SW7/
You could pass a callback to someTask2. For example:
someTask2: function(someObj, callback){
$.ajax({
url: "someUrl.do",
type: "POST",
data: ({"id": rowObject.instanceId}),
dataType: "json",
async:false,
success: function(res){
if(res.prop1 != 'desired'){
setTimeout(function(){someTask2(someObj, callback);}, 2000);
} else {
if (callback != null) {
callback();
}
}
}
}
);
}
Then just pass someTask3 as the callback:
someTask2(someObj, function (){ someTask3(someObj); });

assign value to global variable in javascript

I want to assign value to global variable in javascript from jquery ajax function.
var trueFalse;
$.ajax({
type: "GEt",
url: "url",
data: "text=" + $("#text").val(),
success: function(msg) {
if(msg.match(/OK/) != null) {
trueFalse = "true";
}
else {
trueFalse = "false";
}
}
});
return trueFalse;
here i need the value of trueFalse from success function.
thanks
v.srinath
Your code won't work because the line return trueFalse; executes before the success function runs, since it is called as the result of an asynchronous (as in the A in Ajax) HTTP request. You would need to pass in a callback function to this code, and invoke that in the success function:
function getWithCallback(val, callback) {
var scope = this;
$.ajax({
type: "GET",
url: "url",
data: "text=" + val,
success: function(msg) {
callback.call(scope, msg.match(/OK/) || false);
}
});
}
getWithCallback($("#text").val(), function(result) {
if (result) {
// Do something
}
});
You could try this to validate a form on submit:
var validating = false;
var valid = false;
$('#myform').submit(function(event) {
if (validating) {
return false;
}
if (valid) {
return true;
}
var form = this;
validating = true;
getWithCallback($('#text').val(), function(result) {
if (result) {
valid = true;
form.submit();
}
validating = false;
});
return false;
});
You might also want to look at the jQuery Validation plugin
If you really can't change the application logic, then you have to create a "synchronous" ajax request (by setting async:false in $.ajax options), then it will wait until the "GET" has executed and only then return the value to the caller.
Otherwise, you should rewrite the code so that the success function calls back into some callback function that it can now proceed with whatever has to be done.
Since you are doing this on form.onsubmit, you cannot do an async request. The browser won't know that it should wait until the async request is finished. The benefit of using async is that it does not lock up your scripts/browser, but in this case that is actually what you want.

Categories