3. Displaying All Posts
Alright next step! Now that we can create posts, let's display them.
- Create a post
- Show all posts and show one post
- Make the root route (
/) go to the/posts/indexroute render aposts-indextemplate - Style the template and loop over the
postsobject - Make route to
/posts/showroute (/posts/:id) - Style the template and display the
postobject
- Make the root route (
- Show one post
- Comment on posts
- Create subreddits
- Sign up and Login
- Associate posts and comments with their author
- Make comments on comments
- Vote a post up or down
Connection Script#
Next, you'll need to handle promises from the Mongoose perspective.
I'm going to encourage the use of promises to handle asynchronous transactions. As of Mongoose 5.0 native promises are used by default. Read more
Finally, for testing, we can add an error handler for connection errors.
[action] Open
/data/reddit-db.jsand make the following changes to support connection error handling and promises:
mongoose.connect( url, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false, }, (err) => { assert.equal(null, err); console.log("Connected successfully to database");> // db.close(); turn on for testing });mongoose.connection.on('error', console.error.bind(console, 'MongoDB connection Error:'));Note that the following line we included previously allows us to display debug info from Mongoose in the console:
mongoose.set("debug", true)/Posts/Index Route#
[action] Next, let's create a
posts-indextemplate in ourviewsfolder. Don't worry about it looking fancy right now, we'll spruce it up in a bit. Just have it displayhello worldfor now, or something equally simple.Once that's created, we want to have the root route (
/) render theposts-indextemplate. We also need to then pull thepostsout of the database, and send them along with the response. Let's edit ourINDEXcall in ourposts.jscontroller. Remember to put it AFTER you require all the middleware:
app.get("/", (req, res) => { Post.find({}) .lean() .then((posts) => res.render("posts-index", { posts })) .catch((err) => { console.log(err.message) })})Want more of a challenge?
[challenge]
As a stretch challenge try rewritting the code block above to be async/await. Here is are some video resources:
Callbacks vs Promises vs RxJs Observables vs async/await
And also some text resources:
Async/Await Solution
[solution]
We will not give you the solution to every async/await stretch challenge but hopefully this first one gives you a positive direction to head in.
app.get("/", async (req, res) => { try { const posts = await Post.find({}).lean() return res.render("posts-index", { posts }) } catch (err) { console.log(err.message) }})Now, how clean does that async/await code look?
Try running this and see if your posts-index is being displayed. If so, replace your hello world with the variable {{posts}}. What do you see?

Now, back to those posts! Let's fix them up and display the them properly.
Styling and Looping Over Posts#
[action] If you haven't already, let's go back to our layout template
main.handlebarsand put the whole{{{body}}}object into a div with a container class.
<div class="container">{{{body}}}</div>Great, now let's go back to posts-index.handlebars and make it look good!
[action] To start, we'll put the list of posts into the middle 8 columns of the grid.
<div class="row"> <div class="col-sm-8 col-sm-offset-2">{{!-- more code will go here --}}</div></div>Now that we have {{posts}}, we can use handlebars' built in each operator to loop over the posts, and display each one.
[action] In each post, use bootstrap's
list-groupandlist-group-itemclasses. Display the post title in a div with the classlead, and add an anchor tag that links to the post's url. Finally, addtarget="_blank"to the anchor tag, so that the url opens in a new tab. Here's the fullposts-index.handlebars:
<div class="row"> <div class="col-sm-8 col-sm-offset-2"> <ul> {{#each posts}} <li class="list-group-item"> <div class="lead">{{this.title}}</div> <a href="{{this.url}}" target="_blank">{{this.url}}</a> </li> {{/each}} </ul> </div></div>Now Commit#
$ git add .$ git commit -m 'Users can view a list of posts'$ git pushViewing One Post#
In order to view a single post when a user clicks on it, we'll need to establish a route for individual posts, and render them in their own template.
Let's begin with the user action - clicking on a post in the post-index template.
[action] Replace the current
divfor displaying a post'stitlewith the following:
<div class="lead"><a href="/posts/{{this._id}}">{{this.title}}</a></div>The title is a link to the show page. If we click it, what happens? Error! No route! It's time to fix that.
/Posts/Show Route#
We need the path /posts/:id to resolve to displaying a posts-show template.
[action] open
controllers/posts.js, and add a new GET endpoint. Make sure all middleware requirements happen ABOVE it:
// LOOK UP THE POSTapp.get("/posts/:id", (req, res) => { Post.findById(req.params.id) .lean() .then((post) => res.render("posts-show", { post })) .catch((err) => { console.log(err.message) })})Async/Await stretch challenge!
[challenge]
Refactor the code block above to be async/await. If you get stuck, there are video and text resources linked at the first async/await stretch challenge.
What happens if we refresh? No template!
Making the Template#
Time to template. As a bare minimum we'll use some bootstrap classes to make things look reasonable as we continue to develop the application.
[action] In your
viewsfolder, makeposts-show.handlebarswith the following template:
<div class="row"> <div class="col-sm-6 col-sm-offset-3"> <a href="{{post.url}}" class="lead">{{post.title}}</a> <p>{{post.summary}}</p> </div></div>Product So Far#
Now can you see your post?

What about clicking into your post?

Now Commit#
$ git add .$ git commit -m 'Users can see individual posts'$ git push