I am currently linking a javascript file to an html page, and upon using a function in that javascript file the return value essentially gets erased and shows up as undefined, even though in the function itself the value is defined (that was probably very confusing, i'll just show the code and it should make sense):
functions.js
function addActivity(contactNameSelected, username) {
var returnArray = [];
//post to .php
if(data.added)
{
var newEvent = [];
newEvent['id'] = data.id;
newEvent['date'] = formattedDate;
returnArray.push(true);
returnArray.push(newEvent);
return returnArray; //when i debug, this has a value and is a valid array at this point
}
else
{
returnArray.push(false);
returnArray.push(data.message); //when i debug, this has a value and is a valid array at this point
return returnArray;
}
}
home.html
var response = [];
response = addActivity(contactNameSelected, username); //although valid above, undefined here
if(response[0]) //error b/c response is undefined
{
//do stuff if successful
}
else{
//do other stuff if unsuccessful
}
If i just return a string it works fine, but for some reason if i attempt to return an array it is simply undefined. Why is this?
Thanks!
I'm guessing that the omitted '//post to .php' looks something like
$.post('...php', { ... }, function(data) {
if (data.added) ...
The AJAX response is handled by a callback function, which executes asynchronously. In other words, returnArray is populated well after addActivity has returned.
The return returnArray; statements are useless because you are returning a value from the callback, not from addActivity. The callback is invoked not by your code, but by XHR (in a different execution context) and its return value is discarded.
To properly pass your data back in asynchronous style, we need to tweak your code.
function addActivity(contactNameSelected, username, callback) {
$.post('...', { ... }, function(data) {
var returnArray=[];
if(data.added)
{
...
}
else
{
...
}
callback(returnArray);
});
}
addActivity(contactNameSelected, username, function(response) {
if(response[0])
{
...
}
else
{
...
}
});
Related
I'm trying to make a variable depend on the callback from an AJAX get function, however; I can't seem to get it working. I want to make sure that defaults.context always has a value before proceeding any other code.
What am I doing wrong or how can I achieve this in a proper way?
var defaults = {
currentCase: undefined,
context: {}
}
// Set defaults
function initDefaults(){
defaults.currentCase = getCurrentCase();
defaults.context = getContext(defaults.currentCase, function(object){
console.log(object); // logs the right data
return object;
});
console.log(defaults.context); // logs undefined
}
initDefaults();
// Get the ID of the current case
function getCurrentCase(){
return global_vars.project_ID;
}
function getContext(id, callback){
var obj = {};
$.get(global_vars.template_url + "/includes/load-project-context.php?id=" + id, function(data) {
obj = JSON.parse(data);
}).complete(function() {
callback(obj);
});
}
Thanks in regards,
Enzio
You can use something like
global_vars.template_url + "/includes/load-project-context.php?id=" + id, function(data) {
obj = JSON.parse(data);
}).complete(function() {
callback(obj);
}).fail(function() {
callback(error);
});
This is callback chaining. You can use other callbacks to handle other use cases.
Please check How to know when all ajax calls are complete
You will find there all what you need with quite good explanation
May be you should continue the further code in ajax callback.
// Set defaults
function initDefaults() {
defaults.currentCase = getCurrentCase();
getContext(defaults.currentCase, function(object) {
defaults.context = object; // Continue your code inside here
console.log(defaults.context); // Logs the right data
return object;
});
// This will still return `undefined` because this line will be executed
// before the ajax request finishes.
console.log(defaults.context);
}
Usually, I declare a function with success and fail callbacks as follow
function yoyoyo(param, successCallback, failCallback) {
// do something with param
// ...
if (success) {
successCallback('success');
} else {
failCallback('fail');
}
}
then I will use it like this
yoyoyo('abc', function(success) {
console.log(success);
}, function(err) {
console.log(err);
});
BUT, when I look into Parse Javascript Guide, they guide me to use the function like this (i.e. merge success and fail callbacks in one object?)
var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.get("xWMyZ4YEGZ", {
success: function(gameScore) {
// The object was retrieved successfully.
},
error: function(object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and message.
}
});
How can I declare my function with success and fail callbacks like parse does?
You would just change your function to accept a callbacks arg (call it whatever you want) and then access the handlers off that object:
function yoyoyo(param, callbacks) {
// do something with param
// ...
if (success) {
callbacks.success('success');
} else {
callbacks.error('fail');
}
}
then you would call it with:
yoyoyo('abc', {
success: function(status) {
},
error: function(status) {
}
});
Note though, that your code should check to ensure that the object passed in has both of the methods before attempting to call them.
That method is accepting a object that contains two function pointers. So it's a bit like creating an object thus:
var parameters = {success:function() {}, error:function(){}};
You can simply change your method thus:
function yoyoyo(param, callbacks) {
//Add some error checking to check the callbacks is in the right state
if (typeof callbacks.success != "undefined" && typeof callbacks.error!= "undefined")
{
// do something with param
// ...
if (success) {
callbacks.success('success');
} else {
callbacks.error('fail');
}
}
else {
throw "callbacks must contain a success and error method";
}
}
then call it:
.yoyoto(param, {success:function() {}, error:function(){}});
Looks like what you want is an argument that is an object with success and error functions as attributes
You can declare the function like so
function (param, callbacks) {
// do something with param
// ...
if (success) {
if(callbacks && callbacks.success) callbacks.success('success');
} else {
if(callbacks && callbacks.fail) callbacks.fail('fail');
}
}
As a side note since I see you've tagged node.js, I would also recommend you look at using a single error-first callback, which keeps your functions/apis simple and also follows a rather standard node convention.
I'm having trouble getting a custom validation rule setup with knockout.js for checking if a username already exists. From my understanding, if the return is true then there are no errors, otherwise an error is set.
Here's an example of custom validation
//val is the username in question and searchType is the type of search(username or email)
function checkValue(val, searchType){
if(searchType == 'userName'){
$.post("/users/check_if_exists",{ 'type':'username', 'value': val },function(data) {
var info = JSON.parse(data);
if(info.username_availability == "available"){
return searchType;
//I know this is working because I've alerted the searchtype here and it displays properly
}
else{
return "unavailable";
}
});
}
}
ko.validation.rules['checkIfExists'] = {
validator: function (val, searchType) {
return searchType == checkValue(val, searchType); //if the username is availble, the searchType is returned back so it would return searchType == searchType which should be true meaning there are no errors
},
message: 'This username is taken, please select another.'
};
ko.validation.registerExtenders();
I've checked the network tab and the POST is returning the correct value. If the value is available, I return the searchType. That way, it compares searchType == searchType which should be true. However, that's not the case.
Is there any other way to accomplish what I'm trying to do?
update
Here's what I have as of now
function checkValue(val, searchType, callback) {
var callback = function(data) {
return true;
}
$.post("/users/check_if_exists", { 'type':'username', 'value': val }, function(data) {
info = JSON.parse(data);
if(info.username_availability == "available"){
callback(true);
} else {
callback(false);
}
});
}
ko.validation.rules['checkIfExists'] = {
async: true,
validator: function (val, searchType) {
alert(checkValue(val, searchType));//returns undefined
return checkValue(val, searchType);
},
message: 'This username is taken, please select another.'
};
ko.validation.registerExtenders();
ko.validation calls your validation function.
There are two types of validation functions with regards to the way they pass the success/failure state back to ko.validation: the straight-forward return true/false way, or the "async" way.
The async way exists only because $.ajax exists and it's basically just this: instead of returning a value (which is impossible, as you are using an $.ajax call) you have to somehow notify ko.validation after the ajax response gets back to the browser, right?
So the smart people who wrote this library call your validation function with an extra parameter, a function (callback), that you have to call when the response is available.
function checkValue(val, searchType, callback){
if(searchType == 'userName'){
$.post("/users/check_if_exists",{ 'type':'username', 'value': val },function(data) {
var info = JSON.parse(data);
if(info.username_availability == "available"){
callback(true);
//I know this is working because I've alerted the searchtype here and it displays properly
}
else{
callback(false);
}
});
}
}
ko.validation.rules['checkIfExists'] = {
async: true,
validator: checkValue,
message: 'This username is taken, please select another.'
};
ko.validation.registerExtenders();
Let me turn your code into something more readable:
function checkValue(val) {
var callback = function(data) {
return 'bar';
}
$.post('url', 'data', callback);
}
var x = checkValue('foo');
You are expecting x to be set to 'bar' when that is not the case.
I replaced your anonymous function with "callback" so you better understand that returning something from it does not mean "checkValue" will return anything.
After that your next problem is the fact that AJAX calls are asynchronous.
A validator function accepts three parameters: the value, extra parameters and a callback function. The callback function parameter is designed to aid you in exactly this situation.
Inside the success callback for the $.post you just have to call that callback function for the validator function passing true/false as a parameter.
function checkValue(val, params, callback) {
$.post('url', 'data', function(data) {
if(data === 'bar') {
callback(true);
} else {
callback(false);
}
});
}
checkValue as you have written it always returns undefined. Invoking "return" from inside of a callback function only sets the return value for that callback function (not the "outer function"). If the validator function expects a return value right away (as knockout appears to do) you won't be able get that data asynchronously.
I have a javascript function that posts data to a validation script and grabs a value from there. The callback function on the post request returns a boolean value, and I'm trying to get the entire function to return that boolean value. Right now, the callback function returns the correct value, but the function itself doesn't return anything. Here's the code:
function validate(request_type, request_text) {
$.post("http://www.example.com/ajax/validate.php",{
type: request_type,
text: request_text
}, function(data) {
return (data == "valid");
});
}
I realise that this is sort of a "synchronous" call, and that's not what AJAX is about, but I already have numerous functions in validate.php (database calls, etc.) that I can't implement in Javascript, and I saw threads like this one that talk about using some form of handler.
How would I write a simple handler that will make either the variable data or the result of the boolean comparison data == "valid" available when I use it in an if/else statement (which is where this function is supposed to be used)?
EDIT: For example, one of the if statements that will be using the boolean result:
if (!validate('password',pass_new)) {
$('#pass_new').addClass('error');
$('#pass_confirm_new').addClass('error');
$(error_string.format('Please enter a valid password.')).insertAfter('#pass_confirm_new');
$('#pass_text_short').hide();
$('#pass_text_long').show();
EDIT: The function called with the onsubmit event in my HTML form:
function valid_pass_sett() {
//code to remove errors left over from previous submissions - snipped
pass_old = $('input[name=pass_old]').val();
pass_new = $('input[name=pass_new]').val();
pass_confirm_new = $('input[name=pass_confirm_new]').val();
//some if statements that don't involve AJAX requests - snipped
if (!validate('password',pass_new)) {
$('#pass_new').addClass('error');
$('#pass_confirm_new').addClass('error');
$(error_string.format('Please enter a valid password.')).insertAfter('#pass_confirm_new');
$('#pass_text_short').hide();
$('#pass_text_long').show();
return false;
}
return true;
}
I haven't edited this code to include the updated code that's been posted, but my question is how I return false from it to stop form submission?
function validate(request_type, request_text, callback) {
$.post("http://www.example.com/ajax/validate.php",{
type: request_type,
text: request_text
}, function(data) {
callback(data == "valid");
});
}
And usage would be:
validate(request_type, request_text, function (isValid) {
if(isValid) {
// do something
} else {
// do something if invalid
}
});
Unless you make a synchronous AJAX call (which you probably don't want to do), you simply can't.
If this function is used in several places in your code, your best bet may be to allow it to receive a function.
That way instead of relying on the result being returned from your function to be used in some code, you're actually passing your code directly in, so it is ensured to be able to use the response.
var my_form = $('#my_form');
my_form.submit( valid_pass_sett );
function valid_pass_sett() {
//code to remove errors left over from previous submissions - snipped
pass_old = $('input[name=pass_old]').val();
pass_new = $('input[name=pass_new]').val();
pass_confirm_new = $('input[name=pass_confirm_new]').val();
validate('password', pass_new, pswd_validation_callback); // async validation
return false; // cancel form submission
}
function validate(request_type, request_text, callback ) {
$.post("http://www.example.com/ajax/validate.php",{
type: request_type,
text: request_text
}, callback );
}
function pswd_validation_callback( data ) {
if ( data === 'valid' ) {
// if valid, call the native .submit() instead of the jQuery one
my_form[ 0 ].submit();
} else {
// Otherwise do your thing for invalid passwords.
// The form has already been canceled, so no concerns there.
$('#pass_new').addClass('error');
$('#pass_confirm_new').addClass('error');
$(error_string.format('Please enter a valid password.')).insertAfter('#pass_confirm_new');
$('#pass_text_short').hide();
$('#pass_text_long').show();
}
}
EDIT: Changed to use code posted in question.
EDIT: Updating to work with additional code posted. Narrowing answer down to the named function for clarity.
function validate(request_type, request_text) {
$.post("http://www.example.com/ajax/validate.php",{
type: request_type,
text: request_text
}, function(data) {
return (data == "valid");
}); }
You can't really return from 'validate' the result of the AJAX call. You could try declare a variable before the $.post call, let's call it 'x', and inside the response function assign the value to that variable (x=data=="valid"), and outside the $.post block, but inside the 'validate' function, return that value.
function validate(request_type, request_text) {
var x;
$.post("http://www.example.com/ajax/validate.php",{
type: request_type,
text: request_text
}, function(data) {
x = data == "valid";
});
return x; }
The real problem is that the function 'validate' will continue even if the post call haven't return any value, so it will always be 'false'.
The best thing you can do is call another function INSIDE the response function, so you can assure that the server call is over before getting to the next part.
Edit:
It's been a long time since I posted this answer. The world has changed and so AJAX calls.
Now we have promises ;)
You still cannot return a direct value from a function, but you can return a Promise object, which can be chanined to another Promise, and the second promise will get the data you returned from the first one.
function validate(request_type, request_text) {
var promise = $.ajax("http://www.example.com/ajax/validate.php",{
type: request_type,
text: request_text
});
function getStuff(data) {
//Do something and return the data to the next promise
return data;
}
promise.then(getStuff).then(function(data){
// Do something else with data
});
}
If I understand this question correctly you can achieve what you want by simply storing the returned value into a HTML element and then return that elements value from your custom function:
function validate(request_type, request_text){
$.post("http://www.example.com/ajax/validate.php",{
type: request_type,
text: request_text},
function(data) {
$('#someElement').text(data);
});
//return the data by getting the value of the html element
return $('#someElement').text();
}
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().