I have a small function to validate the user input. In that function I will also check if the email address is already taken. But I have some trouble with the async callback.
I hope anyone could give me a hint, how I could solve this. I use nodejs with the express 3 framework, mongodb and the node-validator library.
This is a part of my validation function:
function check(data, callback) {
mongoose.model('User', User).count(data, function (err, count) {
callback(err, !! count);
});
};
function validate(email, password, confirm) {
var v = new Validator(),
errors = new Array();
v.error = function (msg) {
errors.push(msg);
};
check({email: email}, function (err, exists) {
v.check(exists, { email: 'E-Mail is already taken' }).equals(false);
});
...
return errors;
}
Based on the async callback the variable errors is at the return statement empty. How could I else check if the email address is already in the databse?
You are going to have to add a callback to your validate function. As it stands now, your check function is asynch so you are immediately returning the empty errors array.
function check(data, callback) {
mongoose.model('User', User).count(data, function (err, count) {
callback(err, !! count);
});
};
function validate(email, password, confirm, callback) {
var v = new Validator(),
errors = new Array();
v.error = function (msg) {
errors.push(msg);
};
check({email: email}, function (err, exists) {
if (err) {
return callback(err);
}
v.check(exists, { email: 'E-Mail is already taken' }).equals(false);
callback(null, v);
});
};
// Calling to validate example
server.get("/validate_user_or_whatever", function(req, resp) {
// Call validate with callback
validate(req.param("email"), req.param("password"), true, function(err, validator) {
if (err) {
return resp.json({success: false, message: err.message});
}
var success = validator.isValid; // or something
// Respond with the results
resp.json({success: success});
});
});
Now, your next question is probably going to be how do I run all these validate functions and wait for them to return before calling the validate callback. Good question, take a look at the async module.
You need to think async and pass callbacks that will be called asynchronously.
Quick example:
app.get('/blah', function(req, res) {
// Whatever
validate(email, pass, confirm, function(errors) {
if (errors.length == 0)
resp.send(200, 'blah');
else
resp.send(400, 'blah blah');
});
})
function validate(email, password, confirm, callback) {
var v = new Validator(),
errors = new Array();
v.error = function (msg) {
errors.push(msg);
};
check({email: email}, function (err, exists) {
v.check(exists, { email: 'E-Mail is already taken' }).equals(false);
}, function() {
callback(errors);
});
// ...
return errors;
}
Related
I have the following code
var getUrl = function(callback) {
ref.once('value')
.then(function(snap) {
let article_url = snap.val();
console.log(article_url);
callback(null, article_url); // I dont want to throw an error, so I pass null for the error argument
});
};
var getImage = function(err, data, callback) {
//if (err) throw err; // Check for the error and throw if it exists.
textapi.extract({
url: data,
best_image: true
}, function(error, response) {
if (error === null) {
//console.log(response.image);
if (response.image == null || response.image == "") {
image = "https://www.wefornews.com/wp-content/uploads/2017/01/news-3.jpg"
} else {
image = response.image;
}
}
});
callback(null, image); // Otherwise proceed as usual.
};
var updateDatabase = function(err, data) {
//if (err) throw err; // Check for the error and throw if it exists.
refupdate.update ({
"Article_Image_URL": data
});
console.log('success'); // Otherwise proceed as usual
};
getUrl(getImage);
getImage(updateDatabase);
However I get an error callback is not a function at the line callback(null, image);
The thing is if I remove the updateDatabase function then I get no errors. However when it is within the code I get the error mentioned above.
Can someone please tell me what can be causing this error?
When you call getUrl(getImage), the getImage function is passed as the callback parameter to getUrl. getUrl then calls this callback parameter, passing two parameters.
callback(null, article_url)
but getImage expects three parameters
var getImage = function(err, data, callback)
so callback inside the getImage function is undefined, and when you try to call undefined as a function
callback(null, image)
... you get your callback is not a function error.
Solution
You need to nest your callbacks so the functions are called in the correct order, with the correct parameters.
getUrl(function (err, article_url) {
getImage(err, article_url, function (err, image) {
updateDatabase(err, image);
});
});
This could also be simplified since you want to call updateDatabase directly after getImage completes.
getUrl(function (err, article_url) {
getImage(err, article_url, updateDatabase);
});
Also, in your getImage function, the callback is called before your textapi.extract function completes, which is probably not want you want.
Before
var getImage = function(err, data, callback) {
textapi.extract({
url: data,
best_image: true
}, function(error, response) {
/* code */
});
callback(null, image); // This will get called immediately, without waiting for textapi.extract
};
After
var getImage = function(err, data, callback) {
textapi.extract({
url: data,
best_image: true
}, function(error, response) {
/* code */
callback(null, image); // Callback moved here, so it gets called after textapi.extract completes
});
};
const updateDatabase = async (value) => {
try {
let snap = await ref.once(value);
let article_url = snap.val();
let image = await textapi.extract({
url: article_url,
best_image: true
});
if (image==='') {image = 'https://www.wefornews.com/wp-content/uploads/2017/01/news-3.jpg'}
refupdate.update({
"Article_Image_URL": article_url
});
} catch (err) {
throw err;
}
}
because you don't provide any callback on this call getImage(updateDatabase); (last line) ?
I have written below code in one file:
models/exported.js
module.exports = {
processedList: function(store_name) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) return console.error(err);
return value;
}).select('tid -_id');
}, // Export connection here
};
I have another file in routes
routes/exported.js
var exported = require('../models/exported.js');
var tradeIds = exported.processedList(storename);
console.log('simer'+tradeIds);
}
but I get undefined in console.log. If instead of return statement in processedlist I write console.log then the result gets console. But my requirement is to return data from model file to route file.
I am new to express and node js.
I guidance would be highly appreciated.
Acoording to your question, you want calling a function from route and get return response from your function to route. simple use callback functions.
models/exported.js
module.exports = {
processedList: function (store_name, callback) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) {
callback("error", err)
} else {
callback("success", value)
}
}).select('tid -_id');
}
}
routes/exported.js
var exported = require('../models/exported.js');
exported.processedList('storename', function (err, results) {
if (err == 'error') {
console.log(err);
} else {
console.log(results);
}
});
You are trying sync operation in async environment. processedList may or may not have completed when you try to console log tradeIds. NodeJS would not wait for it to complete because it is asynchronous in nature (by design and it is not a bug). You can pass callback rather than executing this way.
models/exported.js
module.exports = {
processedList: function(store_name, cb) {
var t;
var tradeIds = exported.find({storename: store_name}, function (err, value) {
if (err) return cb(err);
cb(null, value);
}).select('tid -_id');
}, // Export connection here
};
routes/exported.js
var exported = require('../models/exported.js');
exported.processedList(storename, function(err, results) {
if (err) { console.log(err); }
console.log(results);
});
This makes sure that console.log happens only when processedList finishes execution.
How can I put res in a normal function i.e not an exported one which is not part of routes?
function createNewStudent(v,callBackOne){
if (callBackOne) {
studentInfo.callBackOneStudent = callBackOne;
}
// common filter json
var filterjson = common.defaultFilterJson();
filterjson['active'] = true;
filterjson['email'] = v.email;
// student initialization
var student = new Student(v);
async.waterfall([
function (done) {
student.save(function (err) {
if (!err) {
studentInfo.callBackOneStudent();
Employee.update({_id: student.created_by},{"$push": { "students": student._id } }).exec(function (err, employee) { });
done();
}
});
}
}
});
},
function (done) {
var url = config.mailer.studentActivateUrl + student._id;
---error is here-----
res.render('modules/users/server/templates/student-confirmation-email', {
name: student.first_name + ' ' + student.last_name,
appName: 'GAIPP',
url: url
}, function (err, emailHTML) {
done(err, emailHTML, student);
});
}
});
My error is 'res' is not defined. Can anyone please help me to solve this error?
The only way that you can put res in a function is if you somehow supply it to that function at runtime. Remember that res is meaningful only in request handling. Outside of the request handler your function couldn't even know which request to respond to because there might be several requests served at the same time.
If you want to have a function that has access to res then you have those options:
Use a nested function in your request handler, e.g.
app.get('/foo', function (req, res) {
function x() {
// you can use res here
}
x();
});
Add res as an argument:
function x(res) {
// you can use res here
}
app.get('/foo', function (req, res) {
x(res);
});
Another option would be to add a callback to your function that would be passed by the handler:
function x(args, cb) {
// you cannot use res here
// but you can call the callback:
cb(null, 'something');
}
app.get('/foo', function (req, res) {
x(function (err, data) {
if (err) {
// handle error
}
// use res here with data supplied by x()
res(data);
});
});
Instead of using callback your x() function could also return a promise.
I am creating a 'refresh data' function in Node and I cannot figure out where to place the callbacks and returns. The function continues to run. Below is a list of things the function should do. Could someone help out?
Check if a user has an api id in the local MongoDB
Call REST api with POST to receive token
Store token results in a MongoDB
Terminate function
./routes/index.js
router.post('/refresh', function(req, res) {
var refresh = require('../api/refresh');
refresh(req, function() { return console.log('Done'); });
});
../api/refresh.js
var callToken = require('./calltoken');
var User = require('../models/user'); // Mongoose Schema
module.exports = function(req, callback) {
User.findOne( {'username':req.body.username}, function(err, user) {
if(err) { console.log(err) }
if (user.api_id == 0) {
callToken.postToken(req.body.username, callback);
} else { // Do something else }
});
};
./calltoken.js
var request = require('request');
var Token = require('../models/token'); // Mongoose Schema
module.exports = {
postToken: function(user, callback) {
var send = {method:'POST', url:'address', formData:{name:user} };
request(send, function(err, res, body) {
if(err) { console.log(err) }
if (res.statusCode == 201) {
var newToken = new Token();
newToken.token = JSON.parse(body).access_token['token'];
newToken.save(function(err) {
if(err) { console.log(err) }
return callback();
});
}
});
}
};
I'm not an expert in Express but everywhere in you code in lines with if(err) { console.log(err) } you should stop execution (maybe of course not - up to you app) and return 400 or 500 to client. So it can be something like
if(err) {
console.log(err);
return callback(err); // NOTICE return here
}
On successful execution you should call return callback(null, result). Notice null as a first argument - it is according nodejs convention (error always goes as first argument).
I've got following code now:
exports.listByUser = function(req, res) {
Attack.find({user: req.user._id}, function(err, attacks) {
if(err)
return next(err);
for(var i in attacks) {
attacks[i].evaluateFight();
}
res.json(attacks);
});
};
the main problem is that attacks[i].evaluateFight() is called asynchronously, I want to transform it to make sure that [i-1] iteration is done ... and finally call res.json(attacks). I think, it can be done with async, but I don't know how :( Something like this should work, but how can I call attacks.method?
async.eachSeries(attacks, function (callback) {
//something??
callback();
}, function (err) {
if (err) { throw err; }
res.json(attacks);
});
You can leverage async whilst method call to implement the same. However, there is question I have about the callback of evaluateFight because if it is executed asynchronously then there has to be some callback associated with it which will notify if the previous call is succeeded.
The example code can be as follows assuming evaluateFight returns a callback when completed -
exports.listByUser = function(req, res) {
Attack.find({user: req.user._id}, function(err, attacks) {
if(err)
return next(err);
var attacksLength = attacks.length;
var count = 0;
async.whilst(function () {
return count < attacksLength;
},
function (callback) {
attacks[count].evaluateFight(function(err, result){
count++;
callback();
}); // assuming it returns a callback on success
},
function (err) {
// all the iterations have been successfully called
// return the response
res.json(attacks);
});
};