Search code examples
node.jsexpresshandlebars.jsnode-modulesexpress-handlebars

Error: Route.get() requires a callback function but got a [object Undefined] despite module.exports = router; being there?


I am trying to combine my CRUD and TODO application. However, I received this error even though I have added the "module.exports = router;" to my routes js files, server.js file and controller js files. I will add these files below and my folder file structure. Have I missed something?

folder/file structure

server.js file

require('./models/db');
require('./models/task');

const express = require('express');
const path = require('path');
const exphbs = require('express-handlebars');
const bodyparser = require('body-parser');
const logger = require('morgan');
const mongoose = require('mongoose');
const favicon = require('serve-favicon');

const employeeController = require('./controllers/employeeController');

var app = express();

//setting up morgan middleware
app.use(logger('dev'));

app.use(bodyparser.urlencoded({
    extended: true
}));
app.use(bodyparser.json());

app.set('views', path.join(__dirname, '/views/'));
app.engine('hbs', exphbs({ extname: 'hbs', defaultLayout: 'mainLayout', layoutsDir: __dirname + '/views/layouts/' }));
app.set('view engine', 'hbs');

//serving blank favicon to keep from throwing 404 errors
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))

//setting up static path for serving static files
app.use(express.static(path.join(__dirname, 'public')));

//Bringing in the routes
const index = require('./routes/index');
const api = require('./routes/api');

app.use('/', index);
app.use('/api', api);


app.listen(3000, () => {
    console.log('Express server started at port : 3000');
});

app.use('/employee', employeeController);

module.exports = router;

employeeController.js file

const express = require('express');
var router = express.Router();
const mongoose = require('mongoose');
const Employee = mongoose.model('Employee');
const Task = require('../models/task');

router.get('/', (req, res) => {
    res.render("employee/addOrEdit", {
        viewTitle: "Insert Module"
    });
});

router.get('/test', (req, res) => {
    res.render("employee/test");
});


router.get('/edit', (req, res) => {
    res.render("edit");
});

router.get('/index', function(req, res) {
    res.render('employee/index', {layout: 'main.hbs'});
});

router.get('/edit', function(req, res) {
    res.render('employee/edit', {layout: 'main.hbs'});
});

router.post('/', (req, res) => {
    if (req.body._id == '')
        insertRecord(req, res);
        else
        updateRecord(req, res);
});


function insertRecord(req, res) {
    var employee = new Employee();
    employee.fullName = req.body.fullName;
    employee.module = req.body.module;
    employee.mobile = req.body.mobile;
    employee.city = req.body.city;
    employee.save((err, doc) => {
        if (!err)
            res.redirect('employee/list');
        else {
            if (err.name == 'ValidationError') {
                handleValidationError(err, req.body);
                res.render("employee/addOrEdit", {
                    viewTitle: "Insert Module",
                    employee: req.body
                });
            }
            else
                console.log('Error during record insertion : ' + err);
        }
    });
}

function updateRecord(req, res) {
    Employee.findOneAndUpdate({ _id: req.body._id }, req.body, { new: true }, (err, doc) => {
        if (!err) { res.redirect('employee/list'); }
        else {
            if (err.name == 'ValidationError') {
                handleValidationError(err, req.body);
                res.render("employee/addOrEdit", {
                    viewTitle: 'Update Module',
                    employee: req.body
                });
            }
            else
                console.log('Error during record update : ' + err);
        }
    });
}


router.get('/list', (req, res) => {
    Employee.find((err, docs) => {
        if (!err) {
            res.render("employee/list", {
                list: docs
            });
        }
        else {
            console.log('Error in retrieving module list :' + err);
        }
    });
});


function handleValidationError(err, body) {
    for (field in err.errors) {
        switch (err.errors[field].path) {
            case 'fullName':
                body['fullNameError'] = err.errors[field].message;
                break;
            case 'module':
                body['moduleError'] = err.errors[field].message;
                break;
            default:
                break;
        }
    }
}

router.get('/:id', (req, res) => {
    Employee.findById(req.params.id, (err, doc) => {
        if (!err) {
            res.render("employee/addOrEdit", {
                viewTitle: "Update Module",
                employee: doc
            });
        }
    });
});

router.get('/delete/:id', (req, res) => {
    Employee.findByIdAndRemove(req.params.id, (err, doc) => {
        if (!err) {
            res.redirect('/employee/list');
        }
        else { console.log('Error in module delete :' + err); }
    });
});

const sortTask = (a,b) => {
    const taskA = a.task.toLowerCase();
    const taskB = b.task.toLowerCase();
    return (taskA < taskB) ? -1 : (taskA > taskB) ? 1 : 0;
  }

  module.exports = {
    findAll: function (req,res){
      Task
      .find({})
      .then(result => {
        result.sort(sortTask)
        res.render('employee/index', {layout: 'main.hbs'}, {tasks: result})
      })
      .catch(err => res.json(err))
    },

    create: function(req,res){
      Task
      .create(req.body)
      .then(result => {
        // result.sort(sortTask)
        res.json(result)
      })
      .catch(err => res.json(err));
    },

    findOne: function (req,res){
      Task
      .findOne({_id: req.params.id})
      .then(result => res.render('employee/edit', {layout: 'main.hbs'}, result))
      .catch(err => res.json(err))
    },

    complete: function (req,res){
      Task
      .findOneAndUpdate({_id: req.params.id}, {completed: true})
      .then(result => res.json(result))
      .catch(err => res.json(err))
    },

    deleteOne: function (req,res){
      Task
      .remove({_id: req.params.id})
      .then(result => res.json(result))
      .catch(err => res.json(err))
    },

    updateName: function (req,res){
      Task
      .findOneAndUpdate({_id: req.body._id}, {task: req.body.task})
      .then(result => res.json(result))
      .catch(err => res.json(err))
    }
  }

  module.exports = router;

api.js file

const router = require('express').Router();
const taskController = require('../controllers/employeeController');

router
.route('/task/:id')
.get(taskController.findOne)
.put(taskController.complete)
.delete(taskController.deleteOne)

router.post('/create', taskController.create);

router.post('/update', taskController.updateName);

module.exports = router;

index.js file

const router = require('express').Router();
const taskController = require('../controllers/employeeController');

router.get('/', taskController.findAll)

module.exports = router;

Solution

  • You are using module.exports = {...} multiple times in employeeController.js and this is not how it works, please see the docs to learn more

    To fix this just add the router to the first exported object like this:

    module.exports = {
      findAll: function (req,res) {
        ...
      },
      // rest of the functions
      updateName: function(req,res) {
       ...
      },
      router
    }
    
     ̶m̶o̶d̶u̶l̶e̶.̶e̶x̶p̶o̶r̶t̶s̶ ̶=̶ ̶r̶o̶u̶t̶e̶r̶;̶
    

    And then in server.js use the router like this:

    app.use('/employee', employeeController.router);