-
Notifications
You must be signed in to change notification settings - Fork 1
Node JS Routing
Topics covered
- Adding unique id (dynamic values) to path
- Extracting data from unique id (dynamic values)
- Sending data via POST request
- Pass data in
includes(- ..)
- Fetching Query Params
-
In your Model class, you should have a property named
id
. This means every time to create an object you will always have thisid
property. -
In the view, you can access this property as:
<% for (let product of prods) { %> ... <a href="/products/<%=product.id %>" class="btn">Details</a> ... <% } %>
-
First step is to register the route to handle such request.
router.get('/products/:productId', <controller_method_reference>);
-
We can specify dynamic routes parameters by adding colon
:
e.g./products/4
-
Be very careful with placement of routes. Placement matters a lot. Lets say you have 3 routes starting with
/product
router.get('/products', <controller_method_reference>); router.get('/products/:productId', <controller_method_reference>); router.get('/products/delete', <controller_method_reference>);
- Here,
/products/delete
will not be reachable - Whenever we get request for
/delete
, our previous route/products/:productId
will considerdelete
as dynamic parameter and it will get executed instead of/delete
- So you should place dynamic routes with same pattern in the end, as your request gets parsed from top-to-bottom. So correct placement will be:
router.get('/products', <controller_method_reference>); router.get('/products/delete', <controller_method_reference>); router.get('/products/:productId', <controller_method_reference>);
-
-
Second step is to register corresponding controller middleware:
exports.getProduct = (req, res, next) => { const productId = req.params.productId; console.log('productId: ', productId); res.redirect('/'); };
- You can access dynamic parameters from
req
object.req
object has propertyparams
that holds all data. - Name
productId
is the name you set in step 1. - Alternatively, you can write a function in Model to return a specific product matching given id:
static findProductById(id, cb) { getProductsFromFile(products => { const product = products.find(p => p.id === id); if (product) { cb(product); } else { cb([]); } }); }
- Then in controller, we can call that method:
exports.getProduct = (req, res, next) => { const productId = req.params.productId; Product.findProductById(productId, product => { console.log('productId: ', product); }); res.redirect('/'); };
- You can access dynamic parameters from
-
Last step is to assign this controller to router:
router.get('/products/:productId', controller.getProduct);
-
We send the data as the part of request body when working with POST request. We can take help of hidden variables and pass the required data:
<form action="/cart" method="POST"> <button class="btn">Add to Cart</button> <input type="hidden" name="productId" value="<%=product.id %>"> </form>
-
To retrieve this data, we can use
req.body.<param_name>
in controller:exports.postCart = (req, res, next) => { Product.findProductById('req.body.productId', (product) => { res.render('shop/cart', { prods: product, title: 'Cart', path: '/cart' }); }); };
-
Note: To make use of
req.body
, you should havebodyParser
enabled at root level:/* in app.js file */ const express = require('express'); const app = express(); const bodyParser = require('body-parser'); ... app.use(bodyParser.urlencoded({extended: false})); ... app.use('/admin', adminRoutes); app.use(shoppingRoutes);
- Here,
bodyParser
should always come before using any sub-routes, elsereq.body
will always beundefined
.
- Here,
There are two scenarios in which data is passed through includes()
:
-
Inherit Data Passing: This is default. Data gets passed from Controller to HTML file to Includes files. The variable within
includes
file has access to data from Controller file.- Includes File
<!DOCTYPE html> <html lang="en"> <head> <title><%=title %></title>
- HTML file
<%- include('../includes/head') %> </head>
- Controller
exports.getIndex = (req, res, next) => { res.render('shop/index', { title: 'Index', }); };
- Includes File
-
Manual Data Passing: When you need to pass data which is not inherit by controller but by temporary process like loop etc. then in that case you manually pass data as object as second argument to
includes()
method.- Includes File
<form action="/cart" method="POST"> <input type="hidden" name="productId" value="<%=product.id %>"> </form>
- HTML file
<% for (let product of prods) { %> <article class="card product-item"> <div class="card__actions"> <a href="/products/<%=product.id %>" class="btn">Details</a> <%- include('../includes/add-to-cart', {product: product}) %> </div> </article> <% } %>
- Includes File
- You can fetch query params from URL
https://abc.pqr/path?edit=true
using:req.query.<quaery_param_name> i.e. req.query.edit
- You can then pass this value to view or use within controller for logic processing:
exports.getEditProduct = (req, res, next) => { const editMode = req.query.edit; res.render('admin/edit-product', { title: 'Edit Product', editing: editMode }); }