EN VI

Node.js - unable to fetch data from body in ejs web application?

2024-03-09 23:00:30
How to Node.js - unable to fetch data from body in ejs web application

i am creating an web app using nodejs, ejs template, mongodb and express. i have created multiple routes. for user as well as other databases. i am successfully able to fetch the from post request of /register route. but unable to fetch anything from body of /admin/blog/edit/:id route. there are zero error in browser as well as console. but i get empty object when i fetch the body.

this is my app.js code:

if (process.env.NODE_ENV !== 'production') {
    require('dotenv').config()
}



const express = require('express');
const mongoose = require('mongoose');
const ejsLayouts = require('express-ejs-layouts');
const cors = require('cors');
const passport = require('passport');
const flash = require('express-flash');
const session = require('express-session');
const methodOverride = require('method-override');
const webRoutes = require('./routes/webRoutes');
const userRoutes = require('./routes/userRoutes');
const initializePassport = require('./passport-config');

const app = express();

app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/public'));

app.set('view engine', 'ejs');
app.use(ejsLayouts);

app.use(function(req, res, next) {
    res.locals.currentPage = req.path;
    next();
});


app.use("/", webRoutes);
app.use("/admin", userRoutes);

mongoose.connect('mongodb://127.0.0.1:27017/myDB');

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

this is my userRotes.js code:

if (process.env.NODE_ENV !== 'production') {
    require('dotenv').config()
}


let express = require('express');
const app = express();
const router = express.Router();
const bcrypt = require('bcrypt');
const passport = require('passport');
const flash = require('express-flash');
const session = require('express-session');
const methodOverride = require('method-override');
const fs = require('fs');
const path = require('path');
// const User = require('../models/userModel');
const { Blog, Contact, JobOpening, User } = require('../models/dbModels');

const initializePassport = require('../passport-config')
initializePassport(
    passport, 
    email => users.find(user => user.email === email),
    id => users.find(user => user.id === id)
)



router.use(flash())
router.use(session({
    secret: process.env.SECRET_KEY,
    resave: false,
    saveUninitialized: false
}))
router.use(passport.initialize())
router.use(passport.session())
router.use(methodOverride('_method'))

// Function to get JavaScript filenames
function getAdminJSFiles() {
    const adminJsDir = path.join(__dirname, '..', 'public', 'javascript', 'admin');
    const files = fs.readdirSync(adminJsDir);
    const jsFiles = files.filter(file => file.endsWith('.js'));
    return jsFiles;
}

// Function to get JavaScript filenames
function getAdminCSSFiles() {
    const adminCSSDir = path.join(__dirname, '..', 'public', 'styles', 'admin');
    const files = fs.readdirSync(adminCSSDir);
    const cssFiles = files.filter(file => file.endsWith('.css'));
    return cssFiles;
}

const current_user = true;


// Middleware to set layout for all admin routes
router.use((req, res, next) => {
    if (req.originalUrl.startsWith('/admin/login')) {
        // Exclude layout for login routes
        res.locals.layout = 'layout_login';
        return next();
    }
    res.locals.layout = 'layout_admin'; // Specify the admin layout
    res.locals.jsFiles = getAdminJSFiles(); // Pass the jsFiles variable
    res.locals.cssFiles = getAdminCSSFiles(); // Pass the jsFiles variable
    res.locals.user = { name: "dummyUser", email: 'dummyUser@gmail'}
    next();
});


router.use((req, res, next) => {
    if (req.isAuthenticated()) {
        if (req.originalUrl === '/admin/login') {
            return res.redirect('/admin');
        }
        return next();
    }
    if (req.originalUrl === '/admin/login') {
        return next();
    }
    res.redirect('/admin/login');
});

router.get('/', (req, res) => {
    res.render('./admin/admin_home', { current_user: req.body.email, email: req.body.name, params: req.params });
});

router.get('/register', (req, res) => {
    res.render('./admin/admin_register');
});

router.post('/register', async (req, res) => {
    try {
        const hashedPassword = await bcrypt.hash(req.body.password, 10);
        const newUser = new User({
            email: req.body.email,
            password: hashedPassword,
            role: req.body.role
        });
        await newUser.save();
        res.redirect('/admin/login');
    } catch (error) {
        console.error(error);
        res.redirect('/admin/register');
    }
});

router.get('/login', (req, res) => {
    res.render('./admin/admin_login');
});

router.post('/login', passport.authenticate('local', {
    successRedirect: '/admin',
    failureRedirect: '/admin/login',
    failureFlash: true
}));

router.get('/logout', (req, res, next) => {
    req.logout((err) => {
        if (err) { return next(err); }
        res.redirect('/admin');
    });
});

router.get('/blogs', async (req, res) => {
    try {
      const blogs = await Blog.find();
      res.render('./admin/blogs/blog_home', { blogs });
    } catch (err) {
      console.error(err);
      res.status(500).send('Server Error');
    }
  });


router.get('/blogs/add', async (req, res) => {
    try {
      res.render('./admin/blogs/blog_add', { action: `/admin/blog/add`, blog: {} });
    } catch (err) {
      console.error(err);
      res.status(500).send('Server Error');
    }
}); 

router.get('/blogs/edit/:id', async (req, res) => {
    try {
        const blog = await Blog.findById(req.params.id);
      res.render('./admin/blogs/blog_add', { action: `/admin/blogs/edit/${blog._id}`, blog });
    } catch (err) {
      console.error(err);
      res.status(500).send('Server Error');
    }
});

router.post('/blogs/edit/:id', async (req, res) => {
    try {
        // const { title, seo_name, blog_type, author_name, image, banner_image, publish_date, status, trending, long_description } = req.body;
        // const updatedBlog = {
        //     title,
        //     seo_name,
        //     blog_type,
        //     author_name,
        //     image,
        //     banner_image,
        //     publish_date,
        //     status,
        //     trending,
        //     long_description
        // };
        const userID = req.params.id;
        console.log(userID)
        // await Blog.findByIdAndUpdate(req.params.id, updatedBlog);
        const { title } = req.body;
        console.log('Request Body:', req.body); // Log request body
        console.log('Update Query:', { title }); // Log update query
        // await Blog.findByIdAndUpdate(req.params.id, { title });
        res.redirect('/admin/blogs');

    } catch (err) {
      console.error(err);
      res.status(500).send('Server Error');
    }
});


module.exports = router;

this is my blog_add.ejs code:

<div class="content-wrapper">
    <section class="content-header">
        <h1>New</h1>
        <div class="breadcrumb">
            <a class="btn btn-sm btn-info" href="/admin/blogs">Back</a>
        </div>
    </section>
    <section class="content">
        <%- include ('../../partials/admin_form')%>
    </section>
</div>

this is my admin_form.ejs code:

<% // include partials/layouts/include_ckeditor.ejs %>
<div class="box box-default">
    <div class="box-header with-border">
        <h3 class="box-title">Form</h3>
        <div class="box-tools pull-right">
            <button class="btn btn-box-tool" data-widget="collapse">
                <i class="fa fa-minus"></i>
            </button>
        </div>
    </div>
    <% // - var f = locals.f; %>
    <h1><%= blog ? 'Edit blog' : 'Add blog' %></h1>
    <form action="<%= action %>" method="post" enctype="multipart/form-data">
        <div class="box-body">
            <div class="row">
                <div class="col-md-6">
                    <div class="form-group">
                        <label>Title</label>
                        <input type="text" name="title" class="form-control" placeholder="Enter Title" value="<%= blog.title || '' %>">
                    </div>
                    <div class="form-group">
                        <label>SEO Name</label>
                        <input type="text" name="seo_name" class="form-control" placeholder="Enter SEO Name" value="">
                    </div>
                    <div class="form-group">
                        <label>Blog Type</label>
                        <select name="blog_type" class="form-control">
                            <option value="BLOG">BLOG</option>
                            <option value="NEWS">NEWS</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <label>Author Name</label>
                        <input type="text" name="author_name" class="form-control" placeholder="Enter Author Name" value="">
                    </div>
                    <div class="form-group">
                        <label>Image</label>
                        <input type="file" name="image" class="form-control">
                        <p style="color:red;">(530px X 429 px)</p>
                    </div>
                    <div class="form-group">
                        <label>Banner Image</label>
                        <input type="file" name="banner_image" class="form-control">
                        <p style="color:red;">(1015px X 452 px)</p>
                    </div>
                    <div class="form-group">
                        <label>Publish Date</label>
                        <input type="text" name="publish_date" class="form-control" placeholder="Enter Publish Date" id="adrt-datepicker" autocomplete="off" value="">
                    </div>
                    <div class="form-group">
                        <label>Status</label>
                        <input type="checkbox" name="status">
                    </div>
                    <div class="form-group">
                        <label>Trending Blog</label>
                        <input type="checkbox" name="trending">
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="form-group">
                        <label>Long Description</label>
                        <textarea name="long_description" class="form-control"></textarea>
                    </div>
                </div>
            </div>
        </div>
        <div class="box-footer">
            <button type="submit" class="btn btn-primary">Submit</button>
        </div>
    </form>
</div>

<script>
    $(document).ready(function(){
        $("#adrt-datepicker").datepicker({
            dateFormat: 'dd/mm/yy',
            maxDate: 0
        });
    });
</script>

the problem is that when i try to submit form in /admin/blogs/edit/:id path, no data is fetched from the the form. the id is fetched properly but the data is not fetched from the body. this is console.log output for body req:

id: 65eb8dce672a051114e1a090
Request Body: {}
Update Query: { title: undefined }

Solution:

The problem is the form element in the template:

<form action="<%= action %>" method="post" enctype="multipart/form-data">

Attribute enctype="multipart/form-data" sends the form as multipart form data type, the usual type used when for uploading files, but you don't have a middleware on te server which can process that format (the usual tool is multer), which is why req.body is undefined.

If you remove that attribute from the form, the form will be sent as URL encoded type, and express.urlencoded middleware will handle it, and you will get req.body.

However, as you have two fields with file type in your form, image and banner_image, you need to send multipart type request, and on the server, you need to setup multipart middlware, as well as file uploading, destination, naming etc.

So, if you're not uploading files, just remove enctype="multipart/form-data" attribute:

<form action="<%= action %>" method="post">

but in case you're uploading files, on the server, you need to setup upload middleware, for example, you could use multer, and this is how your code might look like (you need to determine how you're going to handle files, where to save them, naming etc., see the linked docs and examples, which are also used here):

// setup upload middleware
const multer  = require('multer');
// setup file destination - you could use in-memory also
const upload = multer({ dest: 'uploads/' });

// you send two file fields, so need to use .fields() method:
const cpUpload = upload.fields([{ name: 'image', maxCount: 1 }, { name: 'banner_image', maxCount: 1 }]);

// add midleware to the route
router.post('/blogs/edit/:id', cpUpload, async (req, res) => {

// handle files, they're in `req.files`
console.log('files', req.files);
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login