Lesson 3: Blog

1 Create a list of posts

For now, we are going to store our blog posts in an object.

The keys will be used as the unique identifier of each blog post.

Each nested object will have 3 keys:

  • a title
  • an excerpt
  • a block of content which can contain HTML
// Create a list of blog posts formatted
// in a way that's usable in our templates
var blogPosts = {
  "my-first-webpage": {
    "title": "My first webpage",
    "excerpt": "I've taken a course at Code at Uni and created my own personal website with HTML and CSS.",
    "content": "\
    <p>My first paragraph as well!</p>\
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vehicula ante nec neque lobortis, fringilla convallis elit dignissim.</p>\
    "
  },
  "hello-world": {
    "title": "Hello World",
    "excerpt": "This is the start of my online journal. I will take about my journey in learning how to code!",
    "content": "\
    <p>Hello World this is a paragraph.</p>\
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In vehicula ante nec neque lobortis, fringilla convallis elit dignissim.</p>\
    "
  },
};
Copy to clipboardapp.js

2 Add a blog route

Let’s create a /blog route where we are going to display a list of our posts.

For that, we need an array of posts. Let’s call it listOfPosts.

We are then going to loop through the keys, and populate this array.

Finally, we are going to pass that array to the template.

// Blog
app.get('/blog', function(req, res) {
  // Create a list of blog posts from our blogPosts object
  // We're doing this because we need to format our data
  // in a way that's usable in our templates
  var listOfPosts = [];
  Object.keys(blogPosts).forEach(function(postId) {
    var post = blogPosts[postId];
    post.id = postId;
    listOfPosts.push(post);
  });

  // Render blog.handlebars with the data it needs
  res.render('blog', {
    posts: listOfPosts,
  });
});
Copy to clipboardapp.js

3 Create the blog template

As the list of posts is an array, we are going to loop through the post by using the {{#each}} helper.

Inside that helper, we can reference the keys of the post object.

{{#each posts}}
  <article>
    <h2>
      <a href="/blog/{{id}}">{{title}}</a>
    </h2>
    <p>
      {{excerpt}}
    </p>
  </article>
{{/each}}
Copy to clipboardblog.handlebars

4 Add the single post route

We also want to view a single post by going to /blog/my-post.

We first to need to create a new route that can handle dynamic parameters.

The idea is that the URL will tell us which post to retrieve information from, and display.

// A single blog post
app.get('/blog/:post_id', function(req, res) {
  // Extract the id from the url entered
  var postId = req.params['post_id'];

  // Find the post
  var post = blogPosts[postId];

  // Show a 404 page if the post does not exist
  if (!post) {
    res.send('Not found');
  } else {
    // Render post.handlebars with the data it needs
    res.render('post', post);
  }
});
Copy to clipboardapp.js

5 Create the single post template

Since we tell the route to render the 'post' template, we need to create that file in views/post.handlebars.

We have enough space to render the full content.

Just make sure to use triple mustache: {{{content}}}. This will allow to render the HTML properly.

{{> header}}

<h1>{{title}}</h1>

<main>
  {{{content}}}
</main>
Copy to clipboardpost.handlebars

6 Add livereload

Add livereload so you don’t have to restart the server.

var livereload = require('livereload');

// Livereload
var server = livereload.createServer({
  exts: ['css', 'handlebars'],
});
server.watch([__dirname + '/views']);
Copy to clipboardapp.js

Add livereload so you don’t have to restart the server.

<script src="http://localhost:35729/livereload.js"></script>
Copy to clipboardfooter.handlebars