This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
The function I called inside jquery returns undefined. I checked the function and it returns correct data when I firebugged it.
function addToPlaylist(component_type,add_to_pl_value,pl_list_no)
{
add_to_pl_value_split = add_to_pl_value.split(":");
$.ajax({
type: "POST",
url: "ds/index.php/playlist/check_folder",
data: "component_type="+component_type+"&value="+add_to_pl_value_split[1],
success: function(msg)
{
if(msg == 'not_folder')
{
if(component_type == 'video')
{
rendered_item = render_list_item_video(add_to_pl_value_split[0],add_to_pl_value_split[1],pl_list_no)
}
else if(component_type == 'image')
{
rendered_item = render_list_item_image(add_to_pl_value_split[0],add_to_pl_value_split[1],pl_list_no)
}
}
else
{
//List files from folder
folder_name = add_to_pl_value_split[1].replace(' ','-');
var x = msg; // json
eval('var file='+x);
var rendered_item;
for ( var i in file )
{
//console.log(file[i]);
if(component_type == 'video')
{
rendered_item = render_list_item_video(folder_name+'-'+i,file[i],pl_list_no) + rendered_item;
}
if(component_type == 'image')
{
rendered_item = render_list_item_image(folder_name+'-'+i,file[i],pl_list_no) + rendered_item;
}
}
}
$("#files").html(filebrowser_list); //Reload Playlist
console.log(rendered_item);
return rendered_item;
},
error: function()
{
alert("An error occured while updating. Try again in a while");
}
})
}
$('document').ready(function()
{
addToPlaylist($('#component_type').val(),ui_item,0); //This one returns undefined
});
The function addToPlaylist doesn't return anything. It makes an asynchronous request, which eventually executes a callback function, which returns something. The original addToPlaylist function is long done and returned by the time this happens though, and the callback function returns to nobody.
I.e. the success: function(msg) { } code executes in a different context and at a later time than the surrounding addToPlaylist function.
Try this to see it in action:
function addToPlaylist() {
$.ajax({
...
success : function () {
alert('second'); // comes after 'first'
return null; // returns to nobody in particular
}
});
alert('first'); // comes before 'second'
return 'something'; // can only return here to caller
}
You're making your request via AJAX, which by definition is asynchronous. That means you're returning from the function before the AJAX request completes. In fact, your return statement is meaningless as it returns from the callback function, not your addToPlaylist function.
You have a couple of choices. The first one is better.
First, you can work with the asynchronous nature of the AJAX request and pass a callback into your addToPlaylist method (much like you're passing in the anonymous callback to the ajax function) and have the AJAX callback, call that function instead of doing the return. That way your request completes asynchronously and doesn't lock up your browser while it's going on.
function addToPlaylist(component_type, add_to_pl_value, pl_list_no, cb )
{
...yada yada yada...
$.ajax({
...
success: function(data) {
...
if (cb) {
cb.apply(this, rendered_item );
}
}
});
}
Second, you can add the option aSync: false to the ajax call. This will force the AJAX call to run synchronously (essentially it just loops until the call returns then calls your callback). If you do that, you need to capture a local variable in your addToPlaylist function inside the callback and assign the value(s) to it from the callback. At the end of the addToPlaylist function, return this variable as the result.
function addToPlaylist(component_type, add_to_pl_value, pl_list_no )
{
...yada yada yada...
var result = null;
$.ajax({
aSync: false,
...
success: function(data) {
...
result = rendered_item;
}
});
return rendered_item;
}
I agree with deceze. What you need to do is perform the necessary action(s) for rendered_item in the success function rather than relying on getting something back from addToPlayList().
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
There is this small function that should logically returns always, but I am getting undefined :-
function hasAccess() {
var dataObj = {
"id" : $scope.groupId
};
$http.post('http://vlinux:9099/GetItems', dataObj).then(
function(response) {
var result = response.data.result;
if(result.includes($scope.screenId)) {
return "ok";
} else {
return "nok";
}
});
}
I started getting downvotes, so wuickly adding, I debugged it and saw http call is bringing expected response and flow is jumping to the right if/else block. Problem is when I am calling this function in a variable its storing undefined.
The call is simple too :-
var allow = hasAccess();
$http.post is not synchronous, but asynchronous.
Thus, all that you have after $http.post is a promise, not the boolean you are expecting.
The documentation show wells how to provide a "callback" to your function, in case of success as well as failure :
// Simple GET request example:
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
// for example : manageWHenOk
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
// for example : manageWHenKO
});
Your function return a result only if the request is fine. If there is an error your function do nothing! I suggest you to add a catch function.
function hasAccess() {
var dataObj = {
"id" : $scope.groupId
};
$http.post('http://vlinux:9099/GetItems', dataObj).then(
function(response) {
var result = response.data.result;
if(result.includes($scope.screenId)) {
return "ok";
} else {
return "nok";
}
}).catch(function (error) {
// do something
});
}
If you still have undefined it means that your template is loaded before to obtain the response. In order to resolve that you can do the request in the resolve method of the $stateProvider.
I'm trying to do a little web in JavaScript + Ajax and I want to do it recursively. I've never used ajax before and the problem is I don't know to finish functions. The code looks like that:
var cont = 0;
var function1 = function (query) {
$.ajax({
url: '...',
data: {
.
.
.
},
success: function (response) {
instructions;
function2(param1, param2);
}
});
};
var function2 = function (query, param2) {
$.ajax({
url: '...',
data: {
.
.
.
},
success: function (response) {
instructions;
function3(param1, param2, param3);
}
});
};
var function3 = function (query, param2, param3) {
if (cont == 2) {
console.log("finish");
return;
}
var test = $.ajax({
url: '...',
data: {
.
.
.
},
success: function (response) {
if (...) {
cont++;
instructions;
var audio = new Audio(...);
audio.play();
audio.onended = function () {
instructions;
function3(query, param2, param3);
return;
};
} else {
instructions;
function3(query, param2, param3);
};
return;
}
});
return;
};
document.getElementById('search-form').addEventListener('submit', function (e) {
e.preventDefault();
function1(document.getElementById('query').value);
}, false);
So basically, when cont == 2I try to get out of javascript function3 with return; but some part of the program ( I don't know if the success: function (response) or the full javascript function3 ) is still running and instructions are being executed.
How could I solve this?
First off, the way to do this properly is to make use of jQuery's deferred objects.
As you have probably noticed, the program doesn't simply wait at the ajax request, and then proceed to the 'success' handler. This is because Javascript uses a non-blocking/waiting model. So you call $.ajax({params,...}), this sends the request, but whatever's after this will then immediately run, without waiting. Then, once the top level function has finished executing and nothing else is running, the response can be processed, and the 'success' handler is invoked.
So how to do this stuff properly? Start by arranging your request functions like this:
function doRequest1() {
return $.ajax({
url: '...',
data: {
.
.
.
}
});
}
function doRequest2(parameter) {
return $.ajax({
url: '...',
data: {
.
p: parameter
.
}
});
}
Notice that we aren't providing a success handler, but we are returning the value that $.ajax returns. This is a deferred object which is used to represent a request which has been sent, but for which a response hasn't been received/handled. You can attach a handler to the object like this:
var r1 = doRequest1();
r1.then(function() {
// Do stuff on success...
});
A nice thing about these objects is that they can be chained using 'then'.
'then' accepts a function which takes the value of the old request and produces a new request to do next:
var allRequests = doRequest1().then(function(result1) {
return doRequest2("hello");
});
The 'allRequests' variable is now a deferred object representing the result of doRequest2. How do you get this result? You use 'then()', just like any other deferred:
allRequests.then(function(result) {
alert("All requests completed. Result of last one: " + result);
});
Make sure that you understand how the result from 1 request can be used to set the parameters for the next one, or even decide which request to make next.
If you don't need one request's result to determine the next, rather, you just want to run a number of requests and wait for them all to complete, you can use a shortcut, 'when':
$.when(doRequest1(),doRequest2(), doRequest3()).then(function(result1,result2,result3) {
// All done
});
Another nice thing about deferreds is that they can be cancelled:
allRequests.abort();
Using the above, hopefully you can see how to restructure your code so you get a sequence of requests with a function to run after all 3 have completed.
Watch the value of your global variable cont through the flow of your program. It may be that it is (never) equal to 2 when function3() is called and that is why your program continues.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 9 years ago.
I have an AJAX function that is called from a javascript function.
Something like this:
(CODE1)
//javascript function calling AJAX.
var function check(){
var status = chkHoliday(date,'Date Chosen');
alert('called');
return status;
}
//AJAX function
function chkHoliday(date,str){
var flag = true;
$.ajax({
type: "GET",
url: someurl,
async: false, //if commented, the alert() from the caller function is called before completion of this function.
dataType: "json",
success: {
flag = false;
}
});
return flag;
}
It works well. The only problem is that since async it is set to false, the web page sort of hangs for a while but then continues to proceed further.
To avoid this I read something about callback functions so i tried this out:
(CODE 2)
//javascript function calling AJAX.
var function check(){
var status;
chkHoliday(date,'Date Chosen',function(retVal){
status = retVal;
});
if(status != null){
alert(status);
return status;
}
else{
alert(true);
return true;
}
}
//AJAX function
function chkHoliday(date,str,callback){
var flag = true;
$.ajax({
type: "GET",
url: someurl,
//async: false, //if commented, the alert() from the caller function is called before completion of this function.
dataType: "json",
success: {
flag = false;
callback(flag);
}
});
//return flag;
}
this worked but the alert was called again before the AJAX function could complete stating "undefined". I don't know what I'm doing wrong.
I want, that the AJAX function should wait till it executes completely and then return to the calling function and run the next statements in the caller function with halting the process (i.e with the use of async). Also i want that the value returned by AJAX should be easily accessible to my caller function.
Put the alert inside the callback function:
chkHoliday(date,'Date Chosen',function(retVal){
status = retVal;
if(status != null){
alert(status);
}
else{
alert(true);
}
});
But note you cannot use the return statement anymore as what you have expected because it is asynchronous.
Since AJAX works asynchronous, it is a problem to place it in a function and return a value. To solve this use deferred with a promise. This will promise the ajax result to the caller. It is slightly different. Here is an example. Works like a charm for me.
Of course you will need to adapt it to your needs, but all you really have to do is create your data object.
var data = {}
function chkHoliday(data) {
var deferred = $.ajax({
method: "post",
url: ajaxURL,
dataType: "json",
data: data
});
return deferred.promise();
}
chkHoliday(data).done(function (response) {
console.log(response);
}
return from your php file with a
echo json_encode(array("success"=>"hello"));
Put the alert inside the callback
functions. or else alerts will work simultaneously inspite of success or error.
I have a problem passing data from a JQuery ajax call back to the calling location. The code in question is below:
jQuery("#button").click(function()
{
for(var i = 0;i < data.length; i++)
{
result = updateUser(data[i]); //result is not populated..
alert(result); //prints 'undefined'
}
});
function updateUser(user_id)
{
jQuery.ajax({
url:"/users/update/"+user_id,
type:"GET",
async: false,
success: (function(data){
//if I alert "data" here it shows up correctly
//but if i try to return it like below
//it does not get passed correctly
return data;
})
});
Any pointers are greatly appreciated
You cannot return value from an AJAX success handler like that. AJAX is asynchronous so execution will proceed to the next line where result is undefined. The only way you can get data back from an asynchronous operation is to use a callback. A callback is a function that gets called when the asynchronous operation finishes what it is doing:
jQuery("#button").click(function () {
for (var i = 0; i < data.length; i++) {
updateUser(data[i], function(result) {
alert(result);
});
}
});
function updateUser(user_id, callback) {
jQuery.ajax({
url: "/users/update/" + user_id,
type: "GET",
success: callback
});
}
Here, you're calling the callback in the success handler of the AJAX call and so now you have access to the data that was returned by the AJAX call.
Have your function return the result of calling jQuery.ajax() - this object implements the jQuery deferred promise interface. That is, an object that promises to return a result some time later.
function updateUser(user_id) {
return jQuery.ajax({...});
}
and then use .done() to register the function to be called when the promise gets resolved:
updateUser(data[i]).done(function(result) {
alert(result);
});
The important part is that deferred objects allow you to complete decouple the initiation of the asynchronous task (i.e. your updateUser function) with what's supposed to happen when that task completes (or fails).
Hence there's no need to pass any callback functions to .ajax, and you can also chain your call with other deferred objects (e.g. animations, other AJAX requests).
Furthermore, you can register as many .done() callbacks as you like, and .fail() callbacks too, without ever having to change updateUser().
The A in ajax is Asynchronous, which means that when the file loaded, the function that started it is done running. Try using jQuery Deferred: http://api.jquery.com/category/deferred-object/
Example:
jQuery("#button").click(function()
{
for(var i = 0;i < data.length; i++)
{
updateUser(data[i]).done(function(result) {
alert(result); //prints 'undefined'
});
}
});
function updateUser(user_id)
{
return jQuery.ajax({
url:"/users/update/"+user_id,
type:"GET",
async: false,
success: (function(data){
...
})
});
}
The function that called the success function is the Ajax request and not the UpdateUser function. So obviously when you return it it will return back from the success callback but not to the UpdateUser function..
Also since the ajax is Asynchronous , buy the time the callback is executed it will come out of the UpdateUser function.. !
pretty sure what is happening (not an expert) but you are returning 'data' for your annonomys function in success and not your whole updateUser function
function updateUser(user_id)
{
var retData;
jQuery.ajax({
url:"/users/update/"+user_id,
type:"GET",
async: false,
success: (function(data){
//if I alert "data" here it shows up correctly
//but if i try to return it like below
//it does not get passed correctly
retData = data;
})
return retData;
});
But like i said, i am no expert.
I want to do the following with my javascript codeblock.
Handle all current and new device requests ie. detect,encrypt,decrypt,etc
Return the result to the calling method
Questions
How can I improve the existing code and get rid of the javascript strict warning:anonymous function does not always return a value.
What is the right way of calling my method?
Any help is greatly appreciated
Thanks!
Herewith the code:
This is how I call the current method
//Contents of SmEditor.js
var response = Ext.decode(Prometheus.DeviceRequestHelper.detect(request_id));
//contents of Sm.js
Ext.ns('myApp')
myApp.DeviceRequestHelper = {
detect:function(request_id){
var task = function(){
Ext.Ajax.request({
url: 'device_requests.php',
params:{
action:'get_device', //in php
'request_id':request_id
},
timeout:30000, //30 seconds
success:function(response){//serverside response
var result = Ext.decode(response.responseText); //convert to js objects
if(result.success == true){//device was detected
cons.log('success,device was detected');
cons.log(result);
Ext.TaskMgr.stop(runTask);
return Ext.encode(result); //javascript strict warning
}else{
if(runTask.taskRunCount >= 10){
//retry limit exceeded
Ext.Msg.show({
title:'Server Failure',
msg:"Detection Failed,Unable to detect device",
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
Ext.MessageBox.getDialog().getEl().setStyle('z-index','80000');
Ext.TaskMgr.stop(runTask);
}
}
},
failure:function(response){
Ext.TaskMgr.stop(runTask);
Ext.Msg.show({
title:'Server Failure',
msg:"Failed, server communication error",
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
Ext.MessageBox.getDialog().getEl().setStyle('z-index','80000');
}
})
}
var runTask = {
run: task,
interval:2000,
repeat:10
};
Ext.TaskMgr.start(runTask);
}
}
To prevent this kind of warning, have the function return a value in all cases, or no cases. At the moment you're only returning a value in one if case; the other cases will not return anything. You can even return undefined to make the warning go away. However, what it is telling you is correct: that a function that sometimes has a return value and sometimes doesn't is a bit weird and suggests you're doing something wrong.
What you seem to want to do is have the inner return in the success method return a value from the detect() method. This is absolutely not possible. The inner function can only return a value to the caller of success, which is Prototype itself. By the time this happens, the detect() method has long since returned.
What you have here is asynchronous code. The detect() method can set up an AJAX request, but it must then return immediate to its caller, which will return control to the browser. At some later time, the HTTP request behind the AJAX call will complete, and then the success function will fire. JavaScript cannot call asynchronous code synchronously, or vice versa.
What you have to do is pass a callback function into your method, and then call it back on completion:
Prometheus.DeviceRequestHelper.detect(request_id, function(response) {
// do something with `response`
});
myApp.DeviceRequestHelper= {
detect: function(request_id, callback) {
...
Ext.Ajax.request({
...
success: function(xhr) {
var result= Ext.decode(xhr.responseText);
if (result.success)
callback(result);
...
},
...
});
},
...
};
(I removed the extra Ext.encode->Ext.decode pair, that just seems like a waste of time.)
First, Your detect method will not return a value and will return immediately(even before the ajax call completes) because the ajax call is asynchronous
Second, there's no point returning a value in your success handler. Instead you should provide a callback function to your detect method like so:
Ext.decode(Prometheus.DeviceRequestHelper.detect(request_id, function(response) {
// do something with your response
}));
// detect function takes a callback function as a parameter
myApp.DeviceRequestHelper = {
detect:function(request_id, funCallback){ // pass in a callback function that is
// called when result was a success
var task = function(){
Ext.Ajax.request({
url: 'device_requests.php',
params:{
action:'get_device', //in php
'request_id':request_id
},
timeout:30000, //30 seconds
success:function(response){//serverside response
var result = Ext.decode(response.responseText); //convert to js objects
if(result.success == true){//device was detected
cons.log('success,device was detected');
cons.log(result);
Ext.TaskMgr.stop(runTask);
// return Ext.encode(result); //javascript strict warning
funCallback(Ext.encode(result)); // ===========> callback function called.
}else{
if(runTask.taskRunCount >= 10){
//retry limit exceeded
Ext.Msg.show({
title:'Server Failure',
msg:"Detection Failed,Unable to detect device",
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
Ext.MessageBox.getDialog().getEl().setStyle('z-index','80000');
Ext.TaskMgr.stop(runTask);
}
}
},
failure:function(response){
// ... failure handing code
}
});
}
var runTask = {
run: task,
interval:2000,
repeat:10
};
Ext.TaskMgr.start(runTask);
}
}