In an $.ajax callback, I want to do something depending on what I receive from the server, which is sending true or false.
The problem is, somewhere in the code, I want a return to fire and it doesn't :
function check()
{
// $.ajax callback(result)
{
console.log(result); //in this case I get 'true' (boolean)
if(!result)
{
// I checked I don't end up here
}
else
{
console.log('well done'); // shows up in the console
return "done";
}
}
return "oops";
}
// later in the code
console.log(check()); // displays "oops" whereas the console.log('well done') has showned up in the console
Parts of the function I didn't give you are mostly CSS effects.
Do you have any idea why a return couldn't fire, or what did I miss ? Thanks in advance !
You are returning a value in a callback, this is why you don't get this value, your code is equivalent to:
function callback (result) {
if (!result) { }
else {
console.log('well done') ;
return "done";
}
}
function _ajax (cb) {
cb (true) ; // Call cb but does not care about the result
return true ;
}
function check() {
ajax (callback) ; // Call ajax but does not care about its result
return "oops";
}
check () ;
If you were doing an asynchronous request, the behaviour would be a bit different, but the idea would remain the same.
You should never do synchronous (a)jax calls, but if you did not care, you could do the following:
function check () {
var res ;
$.ajax ({
success: function (result) {
if (!result) { res = "fail" ; }
else {
console.log('well done') ;
res = "done" ;
}
}
}) ;
return (typeof res === 'undefined') ? "oops" : res ;
}
Related
ES6
I want to keep calling this method until it returns 0 as the result. Sometimes it takes 5 seconds to return a value, sometimes it takes 10 seconds. Sometimes it doesnt return the value but i want to keep going until it returns 0. It should wait until the answer has come back or timeout in 10 seconds to recall it.
This is how i tried this, but it is not working for some reason.
function method() {
doSomething(from_api).then(function (status) {
if(status != "0") {
method();
} else {
console.log("success");
}
}), function (error) {
method();
});
}
What is the right way to do this?
I'm guessing you want something like an asynchronous-while-loop.
function asynchronous_while(promise_provider, condition) {
return promise_provider().then(function (result) {
if (condition(result) === true) {
return asynchronous_while(promise_provider, condition);
} else {
return result;
}
});
}
asynchronous_while(function () { // promise provider
return getStatus(from_api);
}, function (result) { // condition
return result != "0";
}).then(function (result) {
console.log("success", result);
// result should now be "0";
});
How long it takes to complete depends entirely on when getStatus(from_api) returns 0. That might be never. The same pitfalls of a traditional while apply.
Your code works. You just had an extra closing parenthesis.
Change:
}), function (error) {
to:
}, function (error) {
Here is my sample code.
Orchestrator calls the worker with couple of inputs first, upon getting the response, it has to validate whether the response was satisfactory or not.
If satisfactory, just return to the caller.
If not, again, call the same worker or may be different worker with slightly different input and follow the flow.
Here, although, my code calls cb() after the first worker call, it's also going to the second then and errors out "response" is undefined etc..
I could add an extra condition to check whether the 1st response was satisfactory, like need2ndworkercall && validate(response) in 2nd then and get away with it. But wondering what is the right way of dealing with this problem. Appreciate any feedback.
function orchestrateSomething(input, cb){
doSomething(input.a, input.b)
.then(response=>{
if(validate(response)){
cb(buildResultObj(response));
}
else{
return doSomething(input.a)
}
})
.then(response=>{
if(validate(response)){
cb(buildResultObj(response));
}
else{
cb(null,{});
}
})
.catch(error=>cb(error));
}
return value from function and .then(). Also cb function should call passed function which returns value or evaluate parameters and return value passed
function orchestrateSomething(input, cb){
return doSomething(input.a, input.b)
.then(response=>{
if(validate(response)){
return cb(buildResultObj(response));
}
else{
return doSomething(input.a)
}
})
.then(response=>{
if(validate(response)){
return cb(buildResultObj(response));
}
else{
return cb(null,{});
}
})
.catch(error=>cb(error));
}
orchestrateSomething(input, cb) // where `cb` calls function or values passed
.then(function(results) {
console.log(results)
})
.catch(function(err) {
console.log(err)
});
It is possible break the promise chain via simple throw. The trick is to handle it properly on the catch call:
doPromise(...)
.then(...)
.then(result => {
if(condition) {
throw result
}
else {
return doPromise()
}
})
.then(...)
.catch(result => {
if(result instanceof Error) {
// handle error result
}
else {
// handle desired result
}
})
Here's the simpliest demo of such approach: http://plnkr.co/edit/H7K5UsZIueUY5LdTZH2S?p=preview
By the way, if you can generalize then processing function, it becomes possible to make a recursive call:
processCB = (result) => {
if(condition) {
throw result
}
else {
return doPromise()
}
}
catchCB = (result) => {
if(result instanceof Error) {
// handle error result
}
else {
// handle desired result
}
}
doProcess = () => doPromise()
.then(processCB)
.catch(catchCB)
And here's the demo for the second piece: http://plnkr.co/edit/DF28KgBOHnjopPaQtjPl?p=preview
I have a function that is checking for a stored value through chrome.storage.sync.get and inserting a CSS file upon existence of said stored value.
I realize chrome.storage.sync.get is an async function and the return value is not passing back as expected to the makeAggressive() function. However, I don't know how else to write this code to get the result of if (result == 'aggressive') passed to makeAggressive().
How can I retrieve the stored value, check its value and return the result to the calling function?
chrome.tabs.onUpdated.addListener(function(tabId, info, tab) {
if (info.status == 'complete') applyCSS(tab);
});
function applyCSS(tab) {
var tabUrl = tab.url;
if (makeAggressive()) {
chrome.tabs.insertCSS(tab.id, {
file: "aggressive.css"
});
}
}
function makeAggressive() {
chrome.storage.sync.get(function(items) {
var result = items.intensityLevel;
if (result == 'aggressive') {
return true;
}
});
}
Simply pass a callback into the async function.
The callback shall be called once the asynchronous activity is completed.
async_function(function() {
// do something after async_function completes and invokes this callback
});
function async_function(callback) {
something_async(function(result) {
callback(result);
});
}
In your case:
function applyCSS(tab) {
var tabUrl = tab.url;
makeAggressive(function() {
chrome.tabs.insertCSS(tab.id, {
file: "aggressive.css"
});
});
}
function makeAggressive(callback) {
chrome.storage.sync.get(function(items) {
var result = items.intensityLevel;
if (result == 'aggressive') {
callback();
}
});
}
My foreach loop:
jQuery(".custom-checkbox").each(function() {
if (jQuery(this).attr('data-action') == 'true') {
if(deleteQuoteItemFromListing(jQuery(this).attr('data-id'))){
console.log('passed');
}else{
console.log('failed');
}
}
});
And the function is(It's using prototype) but it successes
function deleteQuoteItemFromListing(id){
//does someoperations and on success
delurl = getDelUrl()+id; //baseurl/module/action/delete/id
new Ajax.Request(delurl,{
method: 'get',
onSuccess: function(transport){
return TRUE;
}
})
}
but the problem is all foreach executes at once, and doesn't wait for response from function. It prints failed even the operation is success.
Updated
The other way round i tried first is this
jQuery('.delete-from-quote').click(function() {
var i = 0, j = 0;
jQuery(".custom-checkbox").each(function() {
if (jQuery(this).attr('data-action') == 'true') {
i++;
}
});
if (i == 0) {
alert('please choose product');
return false;
}
jQuery(".custom-checkbox").each(function() {
if (jQuery(this).attr('data-action') == 'true') {
var urlData = "<?php echo $this->getUrl('qquoteadv/index/delete/'); ?>";
urlData += "id/" + jQuery(this).attr('data-id') + "/"
var ajax = jQuery.ajax({
type: "GET",
url: urlData,
success: function(msg) {
j++;
}
})
}
if(i==j){location.reload();} //after completing all, reload the page
});
});
The problem is to know all action completed and reloading the page.
My guess is that the code you've omitted is doing an asynchronous ajax call. Since ajax is asynchronous by default, the code you write there ($.ajax or whatever) starts the process, but then the process continues in the background while your code continues to run.
There's no reasonable way to make the deleteQuoteItemFromListing function wait for the response. (While it's possible to do synchronous ajax, A) it makes for a poor user experience by locking up the browser UI, and B) jQuery will be removing that option at some stage, forcing you to go direct to XHR if you want to keep doing it.)
Instead, restructure your code to embrace the asynchronous nature of web programming by having your function either return a promise or accept a callback, and then resolve the promise or call the callback when done.
Here's a rough idea of what the promise version would look like:
jQuery(".custom-checkbox").each(function() {
if (jQuery(this).attr('data-action') == 'true') {
deleteQuoteItemFromListing(jQuery(this).attr('data-id'))
.done(function(id) {
console.log(id + ' passed');
})
.fail(function(id) {
console.log(id + ' failed');
});
}
});
function deleteQuoteItemFromListing(id){
var d = jQuery.Deferred();
jQuery.ajax(/*...*/)
.done(function() { // This bit assumes the deletion worked if
d.resolveWith(id); // the ajax call worked, and failed if the
}) // ajax call failed; if instead the ajax
.fail(function() { // call always works and returns a flag,
d.rejectWith(id); // adjust accordingly
});
return d.promise();
}
Using callback ensures that the function is executed.
jQuery(".custom-checkbox").each(function () {
if (jQuery(this).attr('data-action') == 'true') {
deleteQuoteItemFromListing(jQuery(this).attr('data-id'), handleData);
}
});
function handleData(data) {
if (data) {
console.log('passed');
} else {
console.log('failed');
}
}
function deleteQuoteItemFromListing(id, callback) {
//does someoperations and on success
delurl = getDelUrl() + id; //baseurl/module/action/delete/id
new Ajax.Request(delurl, {
method: 'get',
onSuccess: function (transport) {
callback(true);
}
})
}
I hope this will work for you. you need to define handleData function outside of the other function.
Use jquery When.
You need to queue those Deferred in an array of Deferred and then apply all of the functions at once.
If one fails all will fail and if all succeeds all will pass.
check this out jQuery When
var queue = [];
var items = 0;
return new $.Deferred(function (deferred) {
$(".custom-checkbox").each(function () {
if ($(this).attr('data-action') == 'true') {
items++;
queue.push(function () {
new Ajax.Request(delurl, {
method: 'get',
onSuccess: function (transport) {
items--;
if(items === 0)
deferred.resolve();
},
onError:function(e){
deferred.reject(e);
}
});
});
}
});
//now resolve all of the deferred fns
$.when(queue).done(function(){
console.log('All went well');
})
.fail(function(e){
console.log('Error ' + e);
});
});
(Part of) Your problem is in this simple statement:
return TRUE;
In JavaScript, the "true" boolean is written in lowercase:
return true;
The interpreter thinks TRUE is a variable, and will throw a ReferenceError, since it's not set / defined anywhere, meaning the function will never return true.
I am having trouble getting a server Meteor.method to return a successful response when I wrap the return in a callback.
It works fine when not wrapped in a call back.
It can throw new Meteor.errors both when wrapped in a call back and when not wrapped in a call back.
Wrapping the Meteor.call on the client side in this exact same fashion works fine.
But, for some reason doing this on the server does not return a response value when return is called.
Here is an example. This is not my exact code but very close. It is very close though.
Meteor.methods({
insertData: insertData
});
function insertData(params){
validateParams(params, function(bool, msg){
if(bool){
//do stuff, like insert records
result = 'thanks a million gagillions';
console.log(result);
return result;
} else {
throw new Meteor.Error(513, msg);
}
});
}
validateParams(params, callback){
for (var key in params) {
value = params[key];
if(_.isEmpty(value) || _.isUndefined(value) || _.isNull(value)) {
callback(false, 'Please enter your "'+ key + '".');
return;
}
}
callback(true);
}
How do I get this to work so that the result is returned?
Your problem is that the return statement belongs to the function you pass to validateParams. It does not belong to the insertData function.
You can see this better if you split the code sections:
function insertFunc(bool, msg) {
// do your work
return result;
}
function insertData(params) {
validateParams(params, insertFunc);
// no return statement..
}
You need to propagate the return value of the callback in validateParams:
validateParams(params, callback){
for (var key in params) {
value = params[key];
if(_.isEmpty(value) || _.isUndefined(value) || _.isNull(value)) {
return callback(false, 'Please enter your "'+ key + '".'); // <----- here
}
}
return callback(true); // <---- and here
}
and then return the result of validateParams in your function:
function insertData(params){
return validateParams(params, function(bool, msg) {
// your code..
});
}
Note: Throwing exceptions work because these are propagated until a try/catch block is reached.
You don't need callbacks here. You might find the straight-line code more readable.
Meteor.methods({
insertData: insertData
});
function insertData(params){
// run validator, allow exception to propagate
validateParams(params);
//do stuff, like insert records
result = 'thanks a million gagillions';
console.log(result);
return result;
}
function validateParams(params){
for (var key in params) {
value = params[key];
if(_.isEmpty(value) || _.isUndefined(value) || _.isNull(value))
throw new Meteor.Error('Please enter your "'+ key + '".');
}
// not strictly necessary, just don't throw exception.
return true;
}