I have 2 different methods that I want to be called when a specific form is filled. I know that I can't have a form with 2 actions so I am just wondering can I call 2 different methods on the same route in Node.js?
I need something like this
router.post('/webmark/addcollection', webmarks.addCollection);
router.post('/webmark/addcollection', webmarks.uploadPicture);
so basically when the button in the form is pressed, the action would redirect to the specific route and the 2 methods would be called.
No, if do it that way, then you will be overwriting the first.
A better approach to that is like below:
router.post('/webmark/addcollection', webmarks.addCollection, webmarks.uploadPicture);
And make sure you make the call to next middleware function here uploadPicture from addCollection handler by adding next() in addCollection middleware on the successful operation.
exports.addCollection = function(req, res, next){
// You logic goes here
// On success operation call next middleware
next();
}
exports.uploadPicture = function(req, res){
// You logic for uploadPicture
}
You can just put the uploadPicture inside the addCollection and it will work as you want.
Your first function receives 3 input (request, response, next), at the end of this function, call next().
Related
i want to know if there is way to create something like an After insert trigger or an asynchronous event that looks regularly through a log table and then apply the changes to another database.
i found something about the use of middlewares or the use of vanilla js functions but because of the different nommenclatures or perhaps the unclear documentation i don't think that's going to work for me.
if anyone could clarify the use of post hooks on update or a promise in a function that would be great.
Basically what i want is a trigger or an event that listens to an order details table, i have 2 types of orders: current and delivered in the first type a field called deliveryDate is empty when it's updated and a value is entered in the field it should capture it and insert it in another Database.
i have a function called update that is executed everytime the route '/myApp' gets a POST request here is an example not far from what i want to do
here is the route:
module.exports = (app) => {
const Something= require('../controllers/something.controller.js')
// Create a new something
app.post('/Myapp', Something.update);}
here is the controller:
const Something = require('../models/something.model.js');
const SomethingLog = require('../models/something.log.model.js');
exports.update = (req, res) => {//function body}
can i create a post hook under the exports.update function like putting the hook in a function and if i do so how will i be able to execute it should i a just assign it to the default post route wouldn't that conflict with the existing route? thank you
You can use mongoose middlewares for this
There are two types in middleware:
Pre
before the operation is carried out
schema.pre('update', function(next) {
// do something
next(); //dont forget next();
});
Post
after the operation is carried out
schema.post('update', function(next) {
// do something
next(); //dont forget next();
});
Note:
you will need to write this middleware in your collection file on which you want this operations to be carried out.
Second, "update" is the operation done on your collection, in case of "pre" middleware will execute before the update on collection and when middleware calls next() it proceeds with the update operation and in case of "post" middleware is executed after the update operation
According to this & this You can add a hook on after updation like this:
schema.post("update", function(doc) {
console.log('Updated');
});
I am submitting a simple contact form in my website's footer (in footer.pug):
form(method="POST" action="contact_form")
input(type='email' name='ct_email' data-name='ct_email' required)
textarea(type='text' name='ct_message' data-name='ct_message' required)
button(type='submit') Send
Since the form is in a template, and the footer template is used throughout the site, the form can be submitted from various routes:
/contact_form
/route1/contact_form
/route1/de/contact_form
and so on...
So now it seems I have to create a handler for all the possible routes:
router.post('/contact_form', function(req, res, next) {
// ...
}
router.post('/route1/contact_form', function(req, res, next) {
// ...
}
How can I easily handle POST requests from all the routes they may be coming from without writing a handler for each?
You can use absolute path reference in your form and it will always submit to the same route even though the form is in different pages.
Try this
form(method="POST" action="/contact_form")
Notice the action changed from contact_form to /contact_form. When you add /, you start referencing the path as an absolute path to the domain. So now, from all pages, the form will be submitted to http://your-domain/contact-form.
Not entirely sure if this is what you mean, but the first argument to ExpressJS's router (I assume that's what router is doing here) can be an array. So instead of:
router.post('/contact_form', function(req, res, next) {
// ...
}
router.post('/route1/contact_form', function(req, res, next) {
// ...
}
You can just do:
router.post(['/contact_form','route1/contact_form'],function(req,res,next){
//some fancy logic to handle both routes.
})
Of course, this requires that you keep a list of these possible routes. On the other hand, you can follow Dinesh Pandiyan's advice, and just use an absolute path. So instead of page1.html, page2.html, page3.html, etc. all having their own own router (or own entry in your router array), you'd essentially be saying "Go to the domain route, then go to this address".
Each request should be handled in separated functions because each request has its own logic. However if you want
function request(req, res, next) {
// Your logic
}
router.post('/contact_form', request) {
// ...
}
router.post('/route1/contact_form', request) {
// ...
}
Right now, I don't have a way to test this code, but I think that will help you.
Here is yet another potential solution - use an independent function as a route handler.
router.post('/a', handlePost);
router.post('/b', handlePost);
router.post('/c', handlePost);
function handlePost(req, res, next){
// use req.path here to figure out what url was called
}
In my website's routes file, I have a function like this:
router.post('/', ctrl1.validate, ctrl2.doSomething)
With the validate function looking like this:
function(req,res,next){
var errors = validator.checkForm('myForm')
if(errors){
res.redirect("/")
}else{
next()
}
}
If I want to pass parameters into the validator function (like the name of forms I want to validate) besides the implied req,res,next, how is that done? I have tried ctrl1.validate(formName) and ctrl1.validate(formName, req,res,next) with function(formName, req,res,next) in the controller, and neither work.
The ideal solution would be to identify what form you're working on from the data passed with the request in the first place. You don't show what that is, so we don't know exactly what to recommend or if that is feasible in this case.
If you can't do that and want to have a generic function that you can use as a request handler in multiple places and you want to pass a parameter to it that is different in each of the different places you use it, then you need to create a function that returns a function.
router.post('/', ctrl1.validate("someFormName"), ctrl2.doSomething)
// definition of ctrl1.validate
validate: function(formName) {
// return a request handler that will knkow which formName to use
return function(req,res,next){
var errors = validator.checkForm(formName)
if(errors){
res.redirect("/")
} else {
next()
}
}
}
When you first call this method, it returns another function that is your actual request handler. That inside function then has access to both req, res, next from the request and has access to the formName that was originally passed in.
I inherited a codebase where it looks like they run middleware in node with the following pattern for Oauth2 passport strategy
module.exports = function (router) {
router.get('/', function (req, res, next) {
passport.authenticate('type', object, function(err, info) {
//pass info object to next middleware
})(req,res,next) <---where does this go?!?
})
}
From my current understanding of the code base, this is actually the last function call in the middleware chain, so could I just add a piece of middleware to the bottom?
Does this sound like the right idea?
And just to clarify what I'm trying to do:
pass data from Oauth callback through middleware function by attaching it to the req
perform DB business logic (create or lookup account)
login with JWT
redirect
This appears to be the "custom callback" method of using passport's authenticate function. If you look at the documentation you can see how they expect it to be used. That said, I don't know what that second argument is supposed to be doing (the object) - it looks like a variable, but I don't see it defined anywhere, and I'm not sure the authenticate method takes arguments in that manner. Also, the custom callback takes three arguments: err, user, and then info... which might trip you up.
Okay, so now to your actual question of "could I just add a piece of middleware to the bottom?" Sort of? The fact is, you're in a routing middleware at that point. If it matches and auth is successful, then you should do whatever code for that route is required inside the custom callback. That's the point of this way of doing things. Alternatively you could use passport.authenticate as a piece of middleware itself (it returns a middleware function usable in the CommonJS pattern.
If you don't want to change up the code, then you could just do this:
module.exports = function (router) {
router.get('/', function (req, res, next) {
passport.authenticate('PICK A VALID TYPE', function(err, user, info) {
// this custom callback will be executed once auth completes
// (either successfully or not
// put code in here to perform DB business logic, login, and redirect
})(req,res,next); <--- this executes the passport.authenticate middleware
})
};
Is it possible with expressjs to have multiple routes calling the same resource, something like that:
app.get('/users/:user_id', users.getOne)
app.get('/users/:username', users.getOne)
I would like to be able to call users.getOne whichever params (:user_id or :username) is used in the get request.
In the users.getOne function, how can I determine wich one was used and build my query according to it?
exports.getOne = function(req, res){
var queryParams = ? // I need help here
Users
.find(queryParams)
...
Thanks!
Possibly related: express.js - single routing handler for multiple routes in a single line
From express's view, both of those routes will match the same set of request URLs. You only need one of them and you can name it to make more sense:
app.get('/users/:key', users.getOne);
//...
// http://stackoverflow.com/a/20988824/266795
var OBJECT_ID_RE = /^[a-f\d]{24}$/i;
exports.getOne = function(req, res) {
var conditions = {_id: req.params.key};
if (!OBJECT_ID_RE.test(req.params.key)) {
conditions = {username: req.params.key};
}
Users.find(conditions)...
If you end up wanting this pattern in many routes throughout your code base, you can extract it into a /users/:user param and use app.param as per #alex's answer, but encapsulate the code to locate the user and stick it on to req.user so the actual route handler can just assume the user has been properly found and loaded by the time it executes, and 404 handling can be centralized as well.
Those are in fact, from express's view, the same route.
No, they are not. One route has :user_id parameter, another one has :username.
This would be a proper solution:
var OBJECT_ID_RE = /^[a-f\d]{24}$/i;
app.param('user_id', function(req, res, next, value, name) {
if (OBJECT_ID_RE.test(value)) {
next()
} else {
next('route')
}
})
app.get('/users/:user_id', users.getOne)
app.get('/users/:username', users.getOne)
app.param set the prerequisite for the route to be called. This way when user_id matches a pattern, first route gets called, otherwise second one.