In my Meteor.methods I have
var post= Posts.insert({...}, function(err,docsInserted){
Posts.update({...} , {...});
});
I want to create an insert model as suggested by David Weldon here.
My model looks like this:
_.extend(Posts, {
ins:function (docID){
return Posts.insert({...});
}
});
In my methods I have this:
var post= Posts.ins(docID, function(err,docsInserted){
Posts.update({...} , {...});
});
How can I use a callback and error handling in the method? I'd like to be able to execute code when the Post is inserted successfully.
Looking at the documentation for collection.insert:
Insert a document in the collection. Returns its unique _id.
Arguments
doc Object
The document to insert. May not yet have an _id attribute, in which case Meteor will generate one for you.
callback Function
Optional. If present, called with an error object as the first argument and, if no error, the _id as the second.
As I understand it, you want to execute a callback function if ins executes successfully. Given that information, here's how I'd structure the code:
_.extend(Posts, {
ins:function (docID, callback){
Posts.insert({...}, function( error, id ) {
if( error ) {
callback( error, null );
} else {
callback( null, id );
}
});
}
});
You don't actually need to return anything. You can just execute the callback function and pass parameters along appropriately. Then you can call the function with the following code:
Posts.ins(docID, function(err,docsInserted){
if( error ) {
// Handle error.
} else {
Posts.update({...} , {...});
}
});
Related
While putting to practice what I've learned so far about ES2015 with Babel, specifically about WeakMaps, I came upon a problem I don't know why it's not working.
I have a WeakMap defined to house data coming from an AJAX call that's only triggered if the value of said WeakMap is undefined.
This is what I came up to:
class User {
constructor( id ) {
id = Number( id );
if( id <= 0 || isNaN( id ) ) {
throw new TypeError( 'Invalid User ID' );
}
_id.set( this, id );
}
getID() {
return _id.get( this );
}
getData() {
let _this = this;
if( _data.get( _this ) === undefined ) {
_this.loadData().done( function( data ) {
// JSON is indeed successfully loaded
console.log( data );
_data.set( _this, data );
// WeakMap is indeed set correctly
console.log( _data.get( _this ) );
});
}
// But here it's undefined again!
console.log( _data.get( _this ) );
return _data.get( _this );
}
loadData() {
return $.get({
url: '/users/' + _id.get( this, data ),
});
}
}
let _id = new WeakMap;
let _data = new WeakMap;
// ---------------
var user = new User( 1 );
console.log( user.getID(), user.getData() ); // 1 undefined
As far as i know, I am setting the WeakMap data correctly, as the User ID is being set and can be retrieved, but the User Data coming from AJAX, although is indeed being set inside the jQuery.done() can't be accessed outside of it.
what i'm doing wrong?
I don't understand JavaScript to the point saying this is the right solution or not but I've searched A LOT, reading countless questions here in Stack Overflow with immense answers that fails to put things ins simple ways so, for anyone interested:
class User {
constructor( id ) {
id = Number( id );
if( id <= 0 || isNaN( id ) ) {
throw new TypeError( 'Invalid User ID' );
}
_id.set( this, id );
}
getID() {
return _id.get( this );
}
getData() {
if( _data.get( this ) === undefined ) {
_data.set( this, this.loadData() );
}
return _data.get( this );
}
loadData() {
return $.getJSON( CARD_LIST + '/player/' + _id.get( this ) );
}
}
let _data = new WeakMap;
// ---------------
var user = new User( 1 );
user.getData().done( function( data ) {
console.log( data );
})
It's not what I had in mind initially and I don't have knowledge to explain the "whys" but, at least this is a palpable working example that I humbly hope that will helps someone else who's trying to extract info from extremely long answers and/or unhelpful/unguided comments.
See How do I return the response from an asynchronous call? for a (lengthy) primer of how to use the result of an asynchronous operation like Ajax.
The short answer is: you cannot use an asynchronously-fetched result if you're synchronously returning a value. Your getData function returns before any Ajax call resolves, so the synchronous return value of getData cannot depend upon any asynchronously-fetched value. This isn't even a matter of "waiting" long enough: the basic principle of JavaScript event handling is that the current function stack (i.e., the current function, and the function that directly called that function, etc.) must resolve entirely before any new events are handled. Handling an asynchronous Ajax result is a new event, so your done handler necessarily will not run until well after your getData function execution is ancient history.
The two general ways to solve your issue are:
Make the Ajax call synchronous
Make the Ajax-fetched value accessible asynchronously outside of getData
You can do #2 by either passing a callback into getData, like
getData(funnction(data) { console.log("If this is running, we finally got the data", data); }
function getData(callback) {
_this.loadData.done(function(data) {
_data.set(this, data);
// etc. etc.
callback(_data.get( _this ));
});
}
So, now the getData is itself asynchronus, does this force you to rewrite any use of `getData you already have, and cause propagation of asynchronous patterns all over your code? Yes, it does.
If you want to use return a promises instead, you could do
getData().then(function(data) {
console.log("Got the data", data);
});
function getData() {
return _this.loadData().then(function(data) {
_data.set(this, data);
// etc. etc.
return _data.get( _this );
});
}
this works because promises allowing chaining then calls. This simply chains then inside and outside the get data function: one then callback is queued inside getData, and the next is queued outside getData. The return value of the first callback is used as the argument of the second. The return value of then is the original promise, so I've simply used the form return mypromise.then(...), which returns the same object as if I'd just done return mypromise (but obviously I haven't set up a callback in that case).
I want to understand one thing about async module in node.js.
I have created a function that map an object from a form to a model object and return this object.
This object is a video with an array of tags.
My question is where can I return the video ? I know normally it is inside the async callback function but if I do that, the object returned is undefined.
Whereas If i return the video object at the end of the whole function, it works but it's not safe as I'm not sure, my async is finished...
By the way, I don't understand the callback function passed in argument to async.each and
called after video.products.push(tag); . What does this function do?
Regards
in my mapping.js :
exports.video = function(object) {
var video = new Video();
video.name = object.name;
video.products = [];
async.each(object.tags, function(tago, callback) {
tag = {
"name" : tago.name
}
video.products.push(tag);
callback();
} ,
function(err) {
if( err ) {
console.log('Error' + error);
throw err;
}
logger.debug("into async" + video);
}
);
logger.debug("end function " );
**//return video;**
}
in my video.js :
var video = mapping.video(object);
logger.debug(video); // return undefined
The simple answer is that you can't - at least not via easy or obvious approach. As its name suggests, async is a library for queuing up asynchronous function calls into the event loop. So your exports.video function simply kicks off a bunch of asynchronous functions, which execute one after the other on an unpredictable time-frame, and then returns immediately. No matter where you try to return your video object within the scope of your function calls which are instantiated by async, the exports.video function will already have returned.
In this case it doesn't really seem like you need asynchronous function calls for what you're doing. I'd suggest that you replace your use of async with something like Underscore's each method, which executes synchronously, instead.
http://documentcloud.github.io/underscore/#each
You'd need to define a callback for your exports.video function e.g..
exports.video = function(object, callback) {
// video code (snip)...
async.each(object.tags,
function eachTag(tag, done) {
// code run for each tag object (snip)...
done();
},
function finished(err) {
// code run at the end (snip)...
callback(thingThatsReturned);
});
};
...and call it like this:
var videoUtils = require('videoUtils');
var tags = getTags();
videoUtils.video({ tags: tags }, function(thingThatsReturned) {
// do something with 'thingThatsReturned'
});
By the way, I don't understand the callback function passed in
argument to async.each and called after video.products.push(tag); .
What does this function do?
The async.each function will call the 'eachTag' function above (2nd argument) for each item in your array. But because it's done asynchronously, and you might do something else async in the function (hit a database/api etc.), it needs to know when that function for that particular array item has finished. Calling done() tells async.each that the function has finished processing. Once all the functions are finished processing (they've all called done()), async.each will run the 'finished' function above (3rd argument).
This is pretty standard async stuff for Node.js, but it can be tricky to get ones head around it at first. Hang in there :-)
Edit: It looks like your code isn't doing anything asynchronous. If it was, then the above code would be the way to do it, otherwise the following code would work better:
exports.video = function(object) {
// video code (snip)...
if (Array.isArray(object.tags)) {
object.tags.forEach(function eachTag(tag) {
// code run for each tag object (snip)...
});
}
return thingThatsReturned;
};
...and call it...
var videoUtils = require('videoUtils');
var tags = getTags();
var thingThatsReturned = videoUtils.video({ tags: tags });
I am new to Javascript programming coming from a Java and Objective C background. I am looking to learn a bit more about Javascript for hybrid mobile applications.
In doing so I am trying to do a login with a call back but I am having a little trouble understanding both the syntax and the way a callback works.
First up I am calling the following login function which just creates an ajax call to fetch some JSON at the minute for testing purposes:
testLogin.loginWithUsername ("test", loginCallback);
This works OK as I can see the 200 OK Status and the expected JSON in logging.
However the call back "loginCallBack" never gets called.
It is as follows:
loginCallback: {
success: function(id) {
alert ('success');
}
failure: function (id, error) {
alert ('failure');
}
}
First off the above gives me a syntax error when I try to run the code, at the success:function(id) line. I can change it and the failure function to = function(id) and it the code runs then but the callback is never called.
I am using a library for the login that states the call back required is an object that needs a success and failure function and the code above is the given example.
So first off I don't understand why the above syntax works in the sample code but gives me an error when I run it?
Secondly am I calling the callback correctly? Both the loginWithUsername call and the loginCallback function are in the same Login.js file.
Here is an example how callback works:
First thing: you need to create a new object containing your functions/methods. Properties and methods are listed comma seperated.
// Creating new object with callback functions
var loginCallback = {
success: function(id) {
alert ('success');
} , // Add a comma
failure: function (id, error) {
alert ('failure');
}
}
function loginWithUsername(username, callback) {
if (username === 'test') {
var successId = 1;
callback.success(successId);
} else {
var errorId, errorMsg;
errorId = 0;
errorMsg = 'Error';
callback.failure(errorId, errorMsg);
}
}
Now you can call the function:
loginWithUsername('test', loginCallback);
And the result should be 'success'.
Edit:
But you can do this without an object, by passing the function directly:
// Creating function
function showMessage(message) {
alert(message);
}
function loginWithUsername(username, callback) {
if (username === 'test') {
callback('success');
} else {
callback('failure');
}
}
// Pass function
loginWithUsername('test', showMessage); // Result: 'success'
loginWithUsername('abcd', showMessage); // Result: 'failure'
First off the above gives me a syntax error when I try to run the code, at the success:function(id) line.
Each property: value pair in an object literal must be separated with a comma.
}, /* Your comma is missing which is why you get a syntax error */
failure:
This:
loginCallback: {
is only acceptable if you want to define a property inside an object literal.
This:
testLogin.loginWithUsername ("test", loginCallback);
is using a variable.
You probably want:
var loginCallback = {
but it is hard to tell without more context.
Hello fellow programmers! I just started an additional programming project and swore to god my code will bo SO much cleaner and easily upgradeable than it has been before.
Then I stumbled upon my "arch enemy" the jQuery AJAX returning. Last time I wanted to return something from an AJAX call I had to bend over and just make the call synchronous. That made things sticky and ugly and I hope that this time I will find something better.
So I have been googling/searching stackoverflow for a while now, and just don't understand this solution many ppl has gotten which is called callback function. Could someone give me an example on how I could exploit these callback functions in order to return my login statuses:
function doLogin(username, password) {
$.ajax({
url: 'jose.php?do=login&user='+username+'&pass='+password,
dataType: 'json',
success: function(data) {
if(data.success==1) {
return('1');
} else {
return('2');
}
$('#spinner').hide();
},
statusCode: {
403:function() {
LogStatus('Slavefile error: Forbidden. Aborting.');
$('#spinner').hide();
return (3);
},
404:function() {
LogStatus('Slavefile was not found. Aborting.');
$('#spinner').hide();
return (3);
},
500:function() {
LogStatus('Slavefile error: Internal server error. Aborting.');
$('#spinner').hide();
return (3);
},
501:function() {
LogStatus('Slavefile error: Not implemented. Aborting.');
$('#spinner').hide();
return (3);
}
},
async: true
});
}
So as you probably know, you cannot use return the way I have done from inside an AJAX call. You should instead use callback functions which I have no idea of how to use.
I'd be VERY greatful if someone could write me this code using callback functions and explaining to me just HOW they WORK.
EDIT:
I REALLY need to return stuff, not use it right away. This function is being called from within another function and should be able to be called from different places without being rewritten even slightly.
/EDIT
Sincerly,
Akke
Web Developer at Oy Aimo Latvala Ab
There are three parts to the basic "I need an asynchronous callback" pattern:
Give the function a callback function parameter.
Call the callback function instead of returning a value.
Instead of calling the function and doing something with its return value, the return value will be passed to your callback function as a parameter.
Suppose your synchronous mind wants to do this:
function doLogin(username, password) {
// ...
return something;
}
switch(doLogin(u, p)) {
case '1':
//...
break;
case '2':
//...
break;
//...
}
but doLogin has to make an asynchronous call to a remote server. You'd just need to rearrange things a little bit like this:
function doLogin(username, password, callback) {
return $.ajax({
// ...
success: function(data) {
if(data.success == 1)
callback('1');
else
callback('2');
},
//...
});
}
var jqxhr = doLogin(u, p, function(statusCode) {
switch(statusCode)) {
case '1':
//...
break;
case '2':
//...
break;
//...
}
});
The jqxhr allows you to reference the AJAX connection before it returns, you'd use it if you needed to cancel the call, attach extra handlers, etc.
A callback is simply a function that runs when certain conditions are met. In this case, it is when ajax has a "success".
You are already using a callback, but you don't recognize it. success: function(data) {} is a callback, but it's just what's called an anonymous function. It has no name or reference, but it still runs. If you want to change this anonymous function to a named function, it is really simple: take the code in the anonymous function, and put it in a named one, and then just call the named one:
[...]success: function(data) {
if(data.success==1) {
return('1');
} else {
return('2');
}
$('#spinner').hide();
}, [...]
should change to:
[...]success: function(){ callbackThingy(data) }, [...]
And now just create the callbackThingy function:
function callbackThingy(data){
if(data.success==1) {
someOtherFunction('1');
} else {
someOtherFunction('2');
}
$('#spinner').hide();
}
Note that the "return" value does nothing. It just stops the callback function, whether you are in an anonymous function or a named one. So you would also have to write a second function called someOtherFunction:
function someOtherFunction(inValue){
if(inValue=='1') {
// do something.
} else if(inValue=='2') {
// do something else.
}
}
The above example is if you have to pass parameters. If you do not need to pass parameters, the setup is simpler:
[...]success: callbackThingy, [...]
function callbackThingy(){
// do something here.
}
From the edit in your original post, I can see that you just need to store a (more) global variable. Try this:
// in the global scope , create this variable:
// (or -- at least -- in the scope available to both this ajax call
// and where you are going to use it)
var valHolder = -1;
// then edit your ajax call like this:
[...]
success: function(data) {
if(data.success==1) {
valHolder = 1;
} else {
valHolder = 2;
}
$('#spinner').hide();
},
[...]
Now you can verify 3 things:
valHolder = -1 means that the ajax call has not yet returned successfully
valHolder = 1 means data.success = 1
valHolder = 2 means data.success != 1.
Another option is to store the variable in an HTML attribute of some element.
Finally, you should probably look at jquery.data for the most jquery way of managing stored data.
Does this help?
Just as a small point of interest, you don't have to include
async : true;
as part of your $.ajax options. The default setting for async is already "true".
Sorry to post this as a response, but until I have 50 rep I can't make a simple comment. (Feel free to help me out with that! ^_^ )
An array of functions, [fn1,fn2,...], each "returns" through a callback, passing an optional error. If an error is returned through the callback, then subsequent functions in the array should not be called.
// one example function
function fn1( callback ) {
<process>
if( error ) callback( errMsg );
else callback();
return;
}
// go through each function until fn returns error through callback
[fn1,fn2,fn3,...].forEach( function(fn){
<how to do this?>
} );
This can be solved other ways, but nonetheless would love the syntactic dexterity to use approach.
Can this be done?
as per correct answer:
[fn1,fn2,fn3,...].every( function(fn) {
var err;
fn.call( this, function(ferr) { err = ferr; } );
if( err ) {
nonblockAlert( err );
return false;
}
return true;
} );
seems this has room for simplification.
for me, much better approach to solve this type of problem - it's flatter, the logic more accessible.
If I understand your question correctly and if you can use JavaScript 1.6 (e.g. this is for NodeJS), then you could use the every function.
From MDN:
every executes the provided callback function once for each element
present in the array until it finds one where callback returns a false
value. If such an element is found, the every method immediately
returns false. Otherwise, if callback returned a true value for all
elements, every will return true.
So, something like:
[fn1, fn2, fn3, ...].every(function(fn) {
// process
if (error) return false;
return true;
});
Again, this requires JavaScript 1.6