1

I'm trying to create a basic CRUD application right now for my group's application but I'm having some trouble with a basic line. To build my crud application, I'm currently using node.js, express, and mongodb. I'm having some trouble with part of my code and I was wondering if you could point me toward the right direction.

(this is a lengthy question. i tried my best to format this so that it wouldn't burn your eyes while reading... sorry if it is hard to read)

context: for reference I'm using this:

https://zellwk.com/blog/crud-express-mongodb/, currently on "Showing quotes to users" 

my problem: every time i initialize res.render(view, locals) my node server crashes. here's the error that i'm getting.

res.render(view, locals)
    ReferenceError: res is not defined
        at Object.<anonymous> (C:\Users\hcqph\xx\xcxx\server.js:35:1)
        at Module._compile (module.js:570:32)
        at Object.Module._extensions..js (module.js:579:10)
        at Module.load (module.js:487:32)
        at tryModuleLoad (module.js:446:12)
        at Function.Module._load (module.js:438:3)
        at Module.runMain (module.js:604:10)
        at run (bootstrap_node.js:393:7)
        at startup (bootstrap_node.js:150:9)
        at bootstrap_node.js:508:3

my code: this is what i have for server.js so far. right now, i'm getting an error whenever i try to import my index.ejs file and whenever i try to import the following lines:

res.render(views, locals)

this is my code for server.js

    const express = require('express');
    const bodyParser = require('body-parser')
    const app = express();
    const MongoClient = require('mongodb').MongoClient

  var db

    MongoClient.connect('mongodb://omittedforprivacy', (err, database) => {
        if (err) return console.log(err)
        db = database

        app.listen(3000, () => {
            console.log('connected to mongoDB successfully. now listening on port 3000 ')
        })

    })

    /* -------- for team documentation --------
    BODYPARSER makes it possible to handle reading data from form element in index.html.  URLENCODED method within body-parser tells body-parser to extract data from form element and add them to the body element property in request object.
    ------------------------------------------------ */ 
    app.use(bodyParser.urlencoded({extended: true}))

    //set 'ejs' template engine, and default extension is ejs
    app.set('view engine', 'ejs')

    //CAN'T FIGURE OUT WHY THIS ISN'T WORKING
    res.render(views, locals)

    /* -------- for team documentation --------
    => = replacement for function

    app.get hand a GET request (read operation)
    ------------------------------------------------ */
    app.get('/', (req, res) => {
        //serves index.html back to browser
        res.sendFile(__dirname + '/index.html')

        //gets list of trips from mlab.com
        var cursor = db.collection('trips').find()

        //retrieves list of trips retrieved from mlab
        db.collection('trips').find().toArray(function(err, results) {
            if(err) return console.log(err)

            //renders index.ejs
            res.render('index.ejs', {trips:results})
        })
    })



    /* app.post handles a create request */
    app.post('/trips', (req, res) => {
        db.collection('trips').save(req.body, (err, result) =>{
            if (err) return console.log(err)

            console.log('saved to database')
            res.redirect('/') //causes browser to reload
        })
    })

Any assistance that you all could provide to help me troubleshoot would be really really appreciated. I've been stuck on this for the past few hours. I thought res was already defined by express? Why am I being told to define res again?

============================================================================= EDIT:

Now i'm getting the following error: Error: Can't set headers after they are sent. this is what i have now:

//getting this to render? 
app.get('views/', (req, res, views, local) =>{ res.render(views,local) })

most recent edit: Thanks to input and suggestions from others, I realized that I needed to change the location and actually explicitly define res.render.

I'm now stuck on the following debugging error:

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:357:11)

I have changed my code as follows:

app.get('/', (req, res) => {
    //serves index.html back to browser
    res.sendFile(__dirname + '/index.html')

    //gets list of trips from mlab.com
    var cursor = db.collection('trips').find()

    //retrieves list of trips retrieved from mlab
    db.collection('trips').find().toArray(function(err, results) {
        if(err) return console.log(err)

        //renders index.ejs
        res.render('index.ejs', {trips:results})
    })
})

//set 'ejs' template engine, and default extension is ejs
app.set('view engine', 'ejs')

//getting this to render? 
app.get('views/', (req, res) =>{
    res.render(views,local)
})


/* app.post handles a create request */
app.post('/trips', (req, res) => {
    db.collection('trips').save(req.body, (err, result) =>{
        if (err) return console.log(err)

        console.log('saved to database')
        res.redirect('/') //causes browser to reload
    })
})

where am i going wrong?

======================================================================= EDIT 2: i was able to get past one debugging error and onto the next. i removed res.render entirely and fixed my header issue by rearranging some of my code. this is my most recent:

/* -------- for team documentation --------
BODYPARSER makes it possible to handle reading data from form element in index.html.  URLENCODED method within body-parser tells body-parser to extract data from form element and add them to the body element property in request object.
------------------------------------------------ */ 
app.use(bodyParser.urlencoded({extended: true}))

//set 'ejs' template engine, and default extension is ejs
app.set('view engine', 'ejs')

/* -------- for team documentation --------
=> = replacement for function

app.get hand a GET request (read operation)
------------------------------------------------ */
app.get('/', (req, res) => {
    //serves index.html back to browser
    res.sendFile(__dirname + '/index.html')

    //gets list of trips from mlab.com
    var cursor = db.collection('trips').find()

    //retrieves list of trips retrieved from mlab
    db.collection('trips').find().toArray(function(err, results) {
        if(err) return console.log(err)

        //renders index.ejs
        res.render('views/index.ejs', {trips:results})
    })
})



/* app.post handles a create request */
app.post('/trips', (req, res) => {
    db.collection('trips').save(req.body, (err, result) =>{
        if (err) return console.log(err)

        console.log('saved to database')
        res.redirect('/') //causes browser to reload
    })
})

now i am working on fixing the following problem:

Error: Failed to lookup view "views/index.ejs" in views direct                      ory "C:\Users\hcqph\gitprojects\crudbeta\views"
2
  • 1
    res.render(views, locals) like it says, res is not defined, its not in a get or post. res isn't a global variable from express. res means response for short. Commented May 1, 2017 at 16:38
  • Not 100% sure, but maybe you need to call res.end(); after your res.render() call in your app.get('/') function. I'm not sure if res.render() calles res.end() or not. If it doesn't then the next time you are calling res.render in your /views endpoint it's trying to send another response and the first one hasn't closed yet. Commented May 1, 2017 at 17:41

2 Answers 2

2
  1. You can call app.render on root level and res.render only inside a route/middleware.
  2. app.render always returns the html in the callback function, whereas res.render does so only when you've specified the callback function as your third parameter. If you call res.render without the third parameter/callback function the rendered html is sent to the client with a status code of 200.

Take a look at the following examples.

app.render

app.render('index', {title: 'res vs app render'}, function(err, html) {
    console.log(html)
});

res.render without third parameter

app.get('/render', function(req, res) {
    res.render('index', {title: 'res vs app render'})
})

res.render with third parameter

app.get('/render', function(req, res) {
    res.render('index', {title: 'res vs app render'}, function(err, html) {
        console.log(html);
        res.send('done');
    })
})
  1. res.render uses app.render internally to render template files.
  2. can't set headers means that you can't get into the body.
  3. res.render() function compiles your template (please don't use ejs), inserts locals there, and creates html output out of those two things.

// here you set that all templates are located in /views directory

app.set('views', __dirname + '/views');

// here you set that you're using `ejs` template engine, and the
// default extension is `ejs`
app.set('view engine', 'ejs');

// here you render `local` template
response.render("local", {local: local_json});

So, the template path is views/ (first part) + local (second part) + .ejs (third part) === views/local.ejs

Sign up to request clarification or add additional context in comments.

6 Comments

thank you so much @King Reload! i have updated my stack question. i have a new debugging problem.. it says that i can't set headers after they are sent. i think what's happening is that i'm trying to send res.render(index.ejs).. but how do i get this to index.ejs to load without rendering views/local first?
@Clark to put the views/local below the index.ejs? you just need to have the res, so you can put the value inside the app.get('/', (req, res) => {...?
thanks for responding. i see where i went wrong now. it makes sense. can i bother you with one more question dude? i really appreciate the help. i'd buy you a coffee irl if i knew you. what does it mean if i'm getting this error: Error: Failed to lookup view "views/index.ejs" in views directory. why would i be getting this error?
you're probably in the wrong directory and I rather have chocolate milk ;P coffee is bad for my teeth and I see the problem is solved?
haha well chocolate milk it is. i changed the directory but i go back to getting the past set headers debugging error. i set the problem is solved because i solved the initial problem but i still have more @_@ is it appropriate if i make a new stackoverflow problem for this new debugging problem? i'm not 100% sure about etiquette here
|
1

Its not working because res is not defined at that point in the code. If you look a few lines lower at your app.get('/') method, res is defined in that function block. You would need to create another endpoint (or use your existing app.get endpoint) - for example,

app.get('/someendpoint', function(req, res) {
    // use res here
    // also must have views and local defined
    res.render(views, local);
});

express will pass in the request and response object to your callback function when declaring a server endpoint.

3 Comments

thanks @Bradstell. I changed it so that app.get is below my defined app.get('/') method but now i'm getting the following error: Error: Can't set headers after they are sent. this is what i have now: //getting this to render? app.get('views/', (req, res, views, local) =>{ res.render(views,local) })
What is views and local here? I do not think express/nodejs will pass those 2 variables into your callback function. It is only req, res that get passed into your callback function. The error cant set headers after they are sent happens when you are trying to send a response twice to the client. You can only set the headers once. I need to see you code to determine exactly where this is happening.
hi @BradStell, i have updated my stack question. i've changed it - i think what's happening is that i'm trying to send res.render(index.ejs).. but how do i get this to index.ejs to load without rendering views/local first?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.