This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
the following code works:
Experimenters = function(db)
{
Object.apply(this, arguments);
this.db = db;
};
util.inherits(Experimenters, Object);
Experimenters.prototype.getAll = function(req, res)
{
return this.db.Experimenter.getAllExperimentersWithExperiments()
.then(function(exptrs) {
res.json(200, exptrs);
})
.catch(function(error) {
res.json(500, error);
});
};
however the code for each of my request handlers is pretty much all the same, so I thought I'd reduce duplicate code by creating a generic request handler:
Experimenters.prototype.handleRequest = function(promise, res)
{
return promise
.then(function(success){
res.json(200, success);
})
.catch(function(error) {
if (error instanceof dbErrors.NotFoundError) {
res.json(404, error);
} else if ((error instanceof dbErrors.ValidationError) ||
(error instanceof dbErrors.UniqueConstraintError)) {
res.json(422, error);
} else {
// unknown error
console.error(error);
res.json(500, error);
}
});
};
And modify my request handlers like this:
Experimenters.prototype.getAll = function(req, res)
{
this.handleRequest(
this.db.Experimenter.getAllExperimentersWithExperiments(),
res);
};
But I'm getting:
TypeError: Object #<Object> has no method 'handleRequest'
the code is called via my routes/index.js
// edited for brevity
var Experimenters = require("../controllers/experimenters");
module.exports.initialize = function(app)
{
var exptrs = new Experimenters(app.db);
app.get("/api/experimenters", exptrs.getAll);
};
which is called from my app.js:
//edited for brevity
var config = require(path.join(__dirname, "..", "config")),
createDB = require(path.join(__dirname, "models")),
routes = require(path.join(__dirname, "routes"));
var db = createDB(config);
app.set("db", db);
// edited for brevity
routes.initialize(app);
Updates:
you are getting this error because you should be binding exptrs to the function like this:
app.get("/api/experimenters", exptrs.getAll.bind(exptrs));
This is because you are passing the function exptrs.getAll as a parameter into the .get function which is called by app and therefore this in exptrs.getAll will be referring to app.
So another solution is to pass an anonymous function to get:
app.get("/api/experimenters", function(){exptrs.getAll()});
Normally when you get errors like Object #<Object> has no method 'handleRequest',
it either means
.prototype.handleRequest() is not defined properly, or
the object that is calling .handleRequest() is not actually the
correct object.
I believe in the return of .handleRequest it should be promise().then(...).catch(...), instead of promise.then(...).catch(...), because just having promise without () you are not calling the function.
Similar to
var b = function(){
return 1
};
function a(c){
return c
}
var d = a(b);
console.log(d);
//it will not log 1, unless
//function a(c){
// return c()
//}
And in .getAll you should be returning this.handleRequest(..) too, rather than just calling it.
I was able to solve this the following way:
First, I noticed that my handleRequest() made no use of 'this', so it could be a simple function
Secondly, I modified handleRequest() by adding a Promise.try() around the promise
handleRequest = function(promise, res)
{
return Promise.try(function(){
return promise;
})
.then(function(success){
res.json(200, success);
})
.catch(function(error) {
if (error instanceof dbErrors.NotFoundError) {
res.json(404, error);
} else if ((error instanceof dbErrors.ValidationError) ||
(error instanceof dbErrors.UniqueConstraintError)) {
res.json(422, error);
} else {
// unknown error
console.error(error);
res.json(500, error);
}
});
};
Related
My friend and I have been struggling with Node.js callbacks since yesterday. We have the following function:
// helperFunction.js
function foo(param) {
request.get({
url: <url>
headers: {<headers>}
}, (err, response, data) => {
array = []
obj.forEach(function (entry) {
// do stuff with array
};
});
return array;
});
}
module.exports.foobar = foo;
then we call that from our app.js.
Since yesterday, we have updated the code to wait for the callback by using a function, like so:
// app.js
//var bar = require('./helperFunction');
//console.log(helperFunction.foobar('param')); // prints undefined
function bar(){
console.log('Log something')
}
foo(bar);
but we don't know how to pass the parameter to foo. I tried to add param (which is a string) to bar but it doesn't work.
For the record, I'm aware of other posts such as this, but I cannot make it work on my code.
In foo you just add a callback parameter and instead of returning you call this function. As a convention, the first parameter of the callback function is the error object. If no error occurred, this object is null and the following parameters are the actual result of the function. Your code didn't include error handling so I added it. If error exists you won't receive any data and foo can't calculate whatever it tries to calculate. In this case, foo should either try to solve the problem itself or propagate the error to its caller.
function foo(param, cb) {
request.get({
url: <url>
headers: {<headers>}
}, (err, response, data) => {
if (err) {
return cb(err);
}
array = []
obj.forEach(function (entry) {
// do stuff with array
};
});
cb(null, array);
});
}
function bar(err, data){
console.log('Log something')
}
foo('some param', bar);
Pass a function to foo. Something like:
foo(() => bar("Hi, I'm something"));
function foo(fn, err) {
if (!err && fn instanceof Function) {
fn();
}
}
function bar(someThing){
console.log(`Log ${someThing}`);
}
What I am trying to get done is extend JSON object in service and then pass it to controller.
JSON came to service from another service which makes backend call.
The code is pretty complicated so I add comments and console.logs:
//get games config object from another service
gamesConfig: gamesConfigService.gamesConfig(),
// prepare name of games icons. This is support function executed in next method
transformSpace: function(subject) {
var ensuredSubject = subject.toString().toLowerCase();
var transformedSubject = ensuredSubject.replace(/ /g, '_');
return transformedSubject;
},
//add iconname property to game config object
extendGameConfig: function() {
var that = this;
this.gamesConfig
.then(function (response) {
console.log(response.data); // this works and console.log my JSON
response.data.map(function(obj) {
return new Promise(function(res){
angular.extend(obj, {
iconname: that.transformSpace(obj.attributes.name) + "_icon.png"
});
});
});
}, function () {
console.log('errror');
});
This contains one support method transformSpace and main method which is not passing data correctly. ( I think )
I'm trying to receive this promise in controller by:
theService.getGamesObj.extendGameConfig()
.then(function (response) {
$scope.allGames = response;
console.log($scope.allGames);
}, function () {
console.log('err')
});
And then I'll use it in view. For now code above doesn't work and give me following error:
TypeError: Cannot read property 'then' of undefined
I've added comments where I think your code has gone wrong
extendGameConfig: function() {
// ***********
// use => functions, that = this wont be needed
var that = this;
// ***********
// if you want this this function to return something, add a return
// this is why you get the
// Cannot read property 'then' of undefined error
// as this function returns undefined
this.gamesConfig
.then(function (response) {
console.log(response.data); // this works and console.log my JSON
// ***********
// you're using .map ... and discarding the result!
response.data.map(function(obj) {
// ***********
// you're creating a promise that never resolves!
// also, why are you promisifying synchronous code?
return new Promise(function(res){
angular.extend(obj, {
iconname: that.transformSpace(obj.attributes.name) + "_icon.png"
});
});
});
}, function () {
console.log('errror');
});
so, try this
extendGameConfig: function() {
return this.gamesConfig
.then(response => {
return response.data.map(obj => {
return angular.extend(obj, {iconname: this.transformSpace(obj.attributes.name) + "_icon.png"});
});
}, function () {
console.log('errror');
});
or, better yet
extendGameConfig: function() {
return this.gamesConfig
.then(response =>
response.data.map(obj =>
angular.extend(obj, {iconname: this.transformSpace(obj.attributes.name) + "_icon.png"})
)
)
.catch(function (err) {
console.log('error', err);
throw err; // log the error, but you'll probably want to reject this promise so the calling code doesn't think there is success?
});
}
In my meteor project, I want to use generic functions in my Meteor.methods
(Mostly because I don't want users to call this functions from the client).
I'm defining this function in another file :
const ldapPing = (callback) => {
try {
ldapAuth.client = createClient({
url: Meteor.settings.private.LDAP.URL,
});
ldapAuth.client.on('error', () => {
throw new Meteor.Error('500', 'Cant join.');
});
callback(null, true);
} catch (exception) {
callback(exception, null);
}
};
And I'm calling it in my meteor methods like this :
'test.ldap': function testLdap() {
try {
const future = new Future();
ldapPing((error, result) => {
console.log('ERROR : ' + error);
console.log('RESULT : ' + result);
if (error) {
future.throw(error);
} else {
future.return(true);
}
});
return future.wait();
} catch (exception) {
throw exception;
}
},
However, the Meteor.error is not returned to the Meteor method and is immediatly throw from the simple function ldapPing, which stops meteor with "Exited with code: 1".
Any idea why ?
(This example is made for this question, ofc in this case there is no benefits to externalize this function)
I have two functions and i can't access from function 2 to function 1.
How can i do that?
class firstController
{
one(req, res)
{
var stamp = request.query("Select 'ALB'+left(newid(),5)+right(newid(),5)+ left(newid(),5)+right(newid(),5) as stamp");
Promise.all([stamp]).then(function(listOfResults)
{
var data = listOfResults[0][0].stamp;
res.send(data);
}).catch(function(err)
{
// ... query error checks
console.log(err);
});
}
two(req, res){
//get the data returned from function 1
console.log(this.one(req, res));
}
}
module.exports = firstController;
i have this error:
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: Cannot read property 'getStamp' of undefined
Thank you
Use this to access functions within the same class in ES6. This is quite complex in ES5 and ES6 compared to other languages and I recommend you have a look at it.
class firstController
{
one(req, res)
{
res.send("hello");
}
two(req, res){
this.one(req, res);
}
}
module.exports = firstController;
UPDATE
To get the data from one into two you'll need to return the result of the Promise like this
one(req, res) {
var stamp = request.query("Select 'ALB'+left(newid(),5)+right(newid(),5)+ left(newid(),5)+right(newid(),5) as stamp");
return Promise.all([stamp]).then(function(listOfResults) {
return listOfResults[0][0].stamp;
}).catch(function(err) {
// ... query error checks
console.log(err);
return err;
});
}
two(req, res){
//get the data returned from function 1
console.log(this.one(req, res));
}
Only use res.send when you want to return data to the client
I'm sure the answer to this one is quite simple but I couldn't figure it out...
Here is my code in Cloud Code:
Parse.Cloud.define("acceptFriendRequest", function(request, response) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query("_User");
var userFrom = new Parse.User();
userFrom = query.get(request.params.userFrom);
console.log(userFrom);
var userTo = new String();
userTo = request.params.userTo;
userFrom.addUnique("friend", userTo);
user.save().then(function (user) {
response.success();
}, function (error) {
console.log(error);
response.error(error);
});
response.success();
});
and here is my code in iOS:
[PFCloud callFunctionInBackground:#"acceptFriendRequest"
withParameters:#{#"userFrom":userFrom.objectId,
#"userTo":[PFUser currentUser].objectId}
block:^(id object, NSError *error) {
if (error) {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
but I'm getting the error:
error = "TypeError: Object [object Object] has no method 'addUnique'\n at main.js:33:12";
I also tried just the plain userFrom.add() method but it came with the same error!
Can anyone help?
You need to wait for get to return the object. I believe get() by itself is just returning null.
query.get(request.params.userFrom, {
success: function(object) {
userFrom = object;
userFrom.addUnique("friend", userTo);
user.save();
},
error: function(object, error) {
// something went wrong
}
});
Those sdk methods return promises, and the pointer columns must be populated with objects, not ids which is what you must be passing. So you need to get both users and chain the asynch calls like this...
Parse.Cloud.useMasterKey();
var userFrom; // so it's available in the second 'then' closure
Parse.Query(Parse.User).get(request.params.userFrom).then(function(user) {
console.log(user);
userFrom = user;
return Parse.Query(Parse.User).get(request.params.userTo);
}).then(function(userTo) {
userFrom.addUnique("friend", userTo);
return userFrom.save();
}).then(function (user) {
response.success(user);
}, function (error) {
console.log(error);
response.error(error);
});