Mongoose passing class functions - javascript

When I pass functions to mongoose, it seems it no longer has a reference to this. Is there a better way to go about this? All functions are simplified for length reasons. I cannot edit the function getUsernameForId to take additional parameters.
I have class:
var class = new function() {
this.func1 = function(data) {
return data + "test";
}
this.func2 = function(data) {
var next = function(username) {
return this.func1(username); // THIS THROWS undefined is not a function
}
mongoose.getUsernameForId(1, func3);
}
}
mongoose is another class like this:
var getUsernameForId = function(id, callback) {
user_model.findOne({"id": id}, function(err, user) {
if(err) {
throw err;
}
callback(user.username);
});
}
How do I resolve the undefined is not a function error. I do not want to duplicate code because func1 is pretty long in reality.

It's not clear from your code how next is used, but if you need it to be invoked with correct this you can try to use Function.prototype.bind method:
this.func2 = function(data) {
var next = function(username) {
return this.func1(username);
}.bind(this);
mongoose.getUsernameForId(1, func3);
}
I assume that you simplified code for the post and next does more things in reality. But if it indeed just returns result of this.func1 then you could shorten it:
var next = this.func1.bind(this);

Related

How to call global function from promise function?

When performing the below function:
try {
Auction.deployed().then(function(contractInstance) {
contractInstance.startAuction(auctionname, duration, { from: buyerAddress }).then(function(result) {
console.log("AUCTION HAS STARTED!!");
console.log(result);
updateAuction(result.receipt);
});
});
} catch (err) {}
}
};
updateAuction = function(data) {
console.log("UPDATE AUCTIONS!");
....
The updateAuction function is not called (even though the console.log functions are working correctly and displaying a message). How can I call the updateAuction function?
This is because of the order in which you're defining the promise and the function.
When you use the syntax updateAuction = function () {}, whether or not you use a var, you must define it above the promise code, otherwise it won't be available. This is in the same way that if you were to write the following, it wouldn't work:
var b = a;
var a = 'Hello!';
This seems quite obvious that a won't be available before it's defined. The same thing applies to functions:
var b = function () {
a();
}
var a = function () {
console.log('Hello');
}
The b function won't have access to a, because it's not yet defined.
If, however, you use the definition of function updateAuction() {}, it will be hoisted, meaning it is defined before anything else.
There are many articles regarding how hoisting works, for example this one from scotch.io and this from Mozilla
var updateAuction = function(data) {
console.log("UPDATE AUCTIONS!");
...
}
try {
Auction.deployed().then(function(contractInstance) {
contractInstance.startAuction(auctionname, duration, { from: buyerAddress }).then(function(result) {
console.log("AUCTION HAS STARTED!!");
console.log(result);
updateAuction(result.receipt);
});
});
} catch (err) {}
You must define your function befor try. correct it like this
var updateAuction = function(data) {
console.log("UPDATE AUCTIONS!");
...
}
try {
Auction.deployed().then(function(contractInstance) {
contractInstance.startAuction(auctionname, duration, { from: buyerAddress }).then(function(result) {
console.log("AUCTION HAS STARTED!!");
console.log(result);
updateAuction(result.receipt);
});
});
} catch (err) {}
;

javascript closures getting variable out and wrong context [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 7 years ago.
what is correct way of writing this in js?
notice this.signals.total is in a wrong context.
articleSchema.pre('save', function(next) {
if (!this.publisher) {
this.publisher = this.url;
}
social.facebook(this.url, function(err, signals) {
//problem is this
this.signals.total = signals.total_count;
});
if (!this.weight) {
this.weight = 1440;
}
var currentDate = new Date();
this.updated_at = currentDate;
if (!this.created_at) {
this.created_at = currentDate;
}
next();
});
this in that case refers to social.facebook correct?
There are several ways I could deal with the problem, e.g. create outside variable, but what is js way?
A simple solution is to store a reference to the correct context:
articleSchema.pre('save', function(next) {
// ...
var that = this; // Store a reference to `this`.
social.facebook(this.url, function(err, signals) {
// Use `that`.
that.signals.total = signals.total_count;
});
// ...
});
Yes, a common solution is to assign the this pointer to a variable outside the inner function like this:
var self = this;
function foo() {
// this would not work, but self does
}
In ECMA-Script 6, you can also use an arrow function instead.
social.facebook(this.url, (err, signals) => {
// this will point to the outer this
});
See this article for more details:
It is totally depends on how the callback is called.
1/ this will be global.
social.facebook = function(url, fn) {
fn(url)
}
2/ this will be social
social.facebook = function(url, fn) {
fn.call(this, url)
}
This way this can also be something weird:
social.facebook = function(url, fn) {
fn.call(weirdObject, url)
}
Create outside variable like the others answer is one way, the other one is bind.
social.facebook(this.url, function(err, signals) {
//problem is this
this.signals.total = signals.total_count;
}.bind(this));

How to add extra parameters to a function callback

I am using a few callbacks in an app that I'm writing. I am using Mongoose models and need to save a few different places. The save function takes a callback, and the callback gets error and model for its parameters, but I'd like to send the callback an extra parameter that the function needs. I'm not sure of the proper syntax to be able to do this. Below is some example code of what I'm going for...
var saveCallBack = function(err, model, email_address){
if(err) {
//handle error
}
else {
//use the third parameter, email_address, to do something useful
}
};
Below, token is a mongoose model. As I said, save takes a callback and gets passed error and model, but I'd like to also send my callback a variable email_address that I figure out at some other point. Obviously the appendParameter function is pseudo-code, but this is the type of functionality that I need.
token.save(saveCallBack.appendParameter(email_address));
If you make that the first parameter instead, you can use .bind().
token.save(saveCallBack.bind(null, email_address));
var saveCallBack = function(email_address, err, model){};
I'm using bind function for appending additional parameters for callbackes
var customBind = function (fn, scope, args, appendArgs) {
if (arguments.length === 2) {
return function () {
return fn.apply(scope, arguments);
};
}
var method = fn,
slice = Array.prototype.slice;
return function () {
var callArgs = args || arguments;
if (appendArgs === true) {
callArgs = slice.call(arguments, 0);
callArgs = callArgs.concat(args);
} else if (typeof appendArgs == 'number') {
callArgs = slice.call(arguments, 0);
}
return method.apply(scope || window, callArgs);
};
}
This customBind function accepts four arguments, first one is original callback function, second is the scope, third is additional parameters (array), and fourth is flag append or replace. If you set last parameter to false than only parameters in array will be available in this function.
and with this function you can simple add new parameters or to override the existing one
var callback = customBind(saveCallBack, this, [array_of_additional_params], true)
in this way all original parameters remain and your parameter will be appended to the end.
No matter how many parameter you defined, the callee will always pass the same parameter inside its process.
but it will be more simple, just use a variable that is visible from outside of the callback.
Eg:
var email = 'yourmail#mail.com';
var saveCallBack = function(err, model){
if(err) {
//handle error
}
else {
alert(email);
}
};
Updated (#Jason): then you can use Immediately-Invoked Function Expression (IIFE)
(function(mail){
var saveCallBack = function(err, model){
if(err) {
//handle error
}
else {
alert(mail);
}
};
token.save(saveCallBack);
}, emailAddress);

How can I get my anonymous JavaScript function to execute withing the calling scope?

I'm trying to make a generic error message function that I can use within any JavaScript function. This function would test for certain validity and stop the calling function dead-cold if it fails.
For example:
var fun = function() {
var a = {};
a.blah = 'Hello';
checkIfExistErrorIfNot(a); // fine, continue on...
checkIfExistErrorIfNot(a.blah); // fine, continue on...
checkIfExistErrorIfNot(a.notDefined); // error. stop calling method ("fun") from continuing
console.log('Yeah! You made it here!');
}
This was my first stab at it:
var checkIfExistErrorIfNot(obj) {
var msg = 'Object does not exist.';
if(!obj) {
return (function() {
console.log(msg);
return false;
})();
}
return true;
}
The returning anonymous function executes just fine. But the calling function still continues. I'm guessing it's because the anon function does not execute in the scope of the calling function.
Thanks.
EDIT
I may not have made my intentions clear. Here is what I normally do in my methods:
saveData: function() {
var store = this.getStore();
var someObj = this.getOtherObject();
if(!store || !someObj) {
showError('There was an error');
return false; // now, 'saveData' will not continue
}
// continue on with save....
}
This is what I'd like to do:
saveData: function() {
var store = this.getStore();
var someObj = this.getOtherObject();
checkIfExistErrorIfNot(store);
checkIfExistErrorIfNot(someObj);
// continue on with save....
}
Now, what would be even cooler would be:
...
checkIfExistErrorIfNot( [store, someObj] );
...
And iterate through the array...cancelling on the first item that isn't defined. But I could add the array piece if I can find out how to get the first part to work.
Thanks
You can use exceptions for that:
var checkIfExistErrorIfNot = function (obj) {
var msg = 'Object does not exist.';
if(!obj) {
throw new Error(msg);
}
}
var fun = function() {
var a = {};
a.blah = 'Hello';
try {
console.log('a:');
checkIfExistErrorIfNot(a); // fine, continue on...
console.log('a.blah:');
checkIfExistErrorIfNot(a.blah); // fine, continue on...
console.log('a.notDefined:');
checkIfExistErrorIfNot(a.notDefined); // error. stop calling method ("fun") from continuing
} catch (e) {
return false;
}
console.log('Yeah! You made it here!');
return true;
}
console.log(fun());

round tripping callbacks

I have an Ajax call with a callback. (I am using YUI for this). The basic call looks like this:
function something() {
var callback1_success = function (o) {…
};
var callback1_failure = function (o) {…
};
var callback1 = {
success: callback1_success,
failure: callback1_failure
};
var callback2_success = function (o) {…
};
var callback2_failure = function (o) {…
};
var callback2 = {
success: callback2_success,
failure: callback2_failure
};
var ajax_params = buildAjaxParams(….);
Y_GET(ajax_params, callback1);
var ajax_params = buildAjaxParams(….); // different stuff
Y_GET(ajax_params, callback2);
} // something
function Y_GET(p_parms, p_callback) {
request = YAHOO.util.Connect.asyncRequest('GET', p_parms, p_callback);
return (request);
} // Y_GET
This all works fine.What I want to do is send the callback to the server, the server will not process the callback parameters and will send them back in the result set.
So, Y_GET will become: Function Y_GET(p_parms, p_callback) {
var parms_to_send = p_parms + “ & passthrough = ” + p_callback;
request = YAHOO.util.Connect.asyncRequest('GET', parms_to_send, local_callback);
return (request);
} // Y_GET
var local_callback = {
success: function (o) {
o.responseText.passthrough.success
},
failure: function (o) {
o.responseText.passthrough.failure
}
}; /* paste in your code and press Beautify button */
if ('this_is' == /an_example/) {
do_something();
} else {
var a = b ? (c % d) : e[f];
}
So, how do I pass a callback function to the server; which returns the name, and call it. If there is another approach, I am open to that, of passing a callback function and acting upon it in the response set.
Thank you.
Off the top of my head, there are a couple of approaches I can think of. eval() is a possibility, but is generally considered something to avoid given the risk of running arbitrary JS code (ultimately this depends on who is providing the string which is being evaled).
I would recommend the following approach:
Create you functions as declarations on a basic JS object.
var Callbacks = {
callback1: function(){ },
callback2: function(){ }
};
Then, use the string returned from your AJAX call as a property indexer into your Callbacks object. I'm not familiar with YUI AJAX requests, but hopefully you get the idea:
var p_callback = function(){
var local_callback = // parse response, get the callback method you want by name/string
Callbacks[local_callback](); // providing arguments as needed, of course
};
YAHOO.util.Connect.asyncRequest('GET', p_parms, p_callback);
By using property accessors on your object you are assured that you are executing only your own callback code, instead of arbitrary JavaScript that may have been included in the response.

Categories