Published at: 2020-07-03 16:00:00
Updated at: 2023-10-01 13:59:37
Hi guys! Today's article, I'm going to explain to you why should you implement the use of Templating than just use the bare bone of HTML. How can it basically change your code while very much able to help you a lot in some ways that you won't understand until you actually implement and use it yourself.
At first when learning how to code JavaScript programming I thought I could code it as Vanilla JavaScript without needing to implement other front-end framework. At least until I have very broad grasp of how Vanilla JavaScript works. So I did continue till now making and building my own portfolio website just using Vanilla JavaScript together with JavaScript based back-end framework like Node JS. I started realizing when I'm in the middle of creating my second version of my portfolio. Specifically when trying to add a blog feature. There's no problem when trying to display all blog post available that I have in my database. But unfortunately, I faced a problem when trying to display a single blog post page.
But before we begin, let me inform you I did too, provide a video sharing session regarding this issue. If you find it much easier to follow me through video form. Then I would suggest you to go to this link. But for those who are more comfortable following in written form. You are welcome to continue doing so. So, with that out of the way. Let's start coding!
Let me explain how it goes through sample code. Let's say we want to display all available blog posts. And then when user click on read more, we want the system to maneuver or basically bring the user to the single blog post page. So in this example I'm going to use just Vanilla JavaScript for the front-end. Node JS as the back-end framework and just a simple object of blog posts act as our data storage. Then, later on we going to change the code to implement a template.
So first, let's create the route to display all blogs available in our database. But before that, make sure you install these packages first:-
index.js
:-/* Dependencies */
// Express Package
const express = require('express')
const app = express()
// Cors
const cors = require('cors')
// Path
const path = require('path')
/* Middlewares */
// cors
app.use(cors())
// body parser
app.use(express.json())
// Static folder
app.use(express.static('web'))
/* Gimmick Data Storage */
let posts = [
{
id: 1,
title: 'Post 1',
description: 'Post One Description'
},
{
id: 2,
title: 'Post 2',
description: 'Post Two Description'
},
{
id: 3,
title: 'Post 3',
description: 'Post Three Description'
}
]
/* Routes */
// 1.0 - page to display All Blog Posts Available
app.get('/blog', async(req, res) => {
// using just NodeJS won't enable use to render a page and send data together when rendering (in my knowledge)
// so the only way to do it, its just render a static html page for now
// - using 'path resolve' to get the path of where 'blog.html' situated
let parentPath = path.resolve(__dirname + '/blog.html', '../')
// - using 'sendFile' to render a static html page of 'blog.html'
res.sendFile(path.join(parentPath + '/views/blog.html'))
})
/* Server Connection */
app.listen(5000, console.log('Server is up and running at port 5000.'))
You might already notice that we don't actually send any blog post data right? That's because with only using just Node JS without implementing or applying any other third party package. Node JS not able to render a page dynamically. The only possible way for us to render a page is by using Node JS sendFile
which is so limited and unable to send data while rendering a page. With the above code, we are only able to serve the page of where the content will be. So where exactly we are able to get our desired blog post data? Let me show you.
blog.html
(Page to display All Blog Post Available):-<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blog</title>
</head>
<body>
<div class="container"></div>
<script src="/js/blog.js"></script>
</body>
</html>
blog.js
(Script to handle fetching of All Blog Post Available):-// create a function to handle data fetching
let dataFromDB = async() => {
// fetch data (All Blog Posts Available) through API URL of '/api/blog'
const res = await fetch('/api/blog')
const json = await res.json()
if(json.message === 'Successful!') {
// update into UI
let posts, htmlTemplate
posts = json.data
posts.forEach(post => {
htmlTemplate = `
<div class="post" id="post-${post.id}">
<h1 class="title">${post.title}</h1>
<p class="desc">${post.description}</p>
/* will bring user to route of '/blog/id' */
<a href="/blog/${post.id}">Read More</a>
</div>
`
// append the template to UI
document.querySelector('.container').insertAdjacentHTML('beforeend', htmlTemplate)
});
} else {
alert('No data fetched from db!')
}
}
dataFromDB()
As you see, we actually able to get data (All Blog Posts Available) by using JavaScript fetch
from the front-end of the system. This is the only way how we can get data from our server or back-end. The only next thing we could do is to create those API URL of route /api/blog
to send/return the data we need like shown below:-
index.js
:-/* Dependencies */
// Express Package
const express = require('express')
const app = express()
// Cors
const cors = require('cors')
// Path
const path = require('path')
/* Middlewares */
// cors
app.use(cors())
// body parser
app.use(express.json())
// Static folder
app.use(express.static('web'))
/* Gimmick Data Storage */
let posts = [
{
id: 1,
title: 'Post 1',
description: 'Post One Description'
},
{
id: 2,
title: 'Post 2',
description: 'Post Two Description'
},
{
id: 3,
title: 'Post 3',
description: 'Post Three Description'
}
]
/* Routes */
// 1.0 - page to display All Blog Posts Available
app.get('/blog', async(req, res) => {
// using just NodeJS won't enable use to render a page and send data together when rendering (in my knowledge)
// so the only way to do it, its just render a static html page for now
// - using 'path resolve' to get the path of where 'blog.html' situated
let parentPath = path.resolve(__dirname + '/blog.html', '../')
// - using 'sendFile' to render a static html page of 'blog.html'
res.sendFile(path.join(parentPath + '/views/blog.html'))
})
// 1.1 - route to handle passing of All Blog Posts Available
app.get('/api/blog', async(req, res) => {
try {
// send All Blog Posts Available
res.json({ message: 'Successful!', data: posts })
} catch(err) {
res.json({ message: 'Unsuccessful!', data: err })
}
})
/* Server Connection */
app.listen(5000, console.log('Server is up and running at port 5000.'))
Up till now, there was no problem to serve our Blog page using this method. But the problem you will definitely face when continuing doing so, is when you want to serve a Single Blog Post page that user will clicked on. Let's create a route to handle the single blog post page.
index.js
:-/* Dependencies */
// Express Package
const express = require('express')
const app = express()
// Cors
const cors = require('cors')
// Path
const path = require('path')
/* Middlewares */
// cors
app.use(cors())
// body parser
app.use(express.json())
// Static folder
app.use(express.static('web'))
/* Gimmick Data Storage */
let posts = [
{
id: 1,
title: 'Post 1',
description: 'Post One Description'
},
{
id: 2,
title: 'Post 2',
description: 'Post Two Description'
},
{
id: 3,
title: 'Post 3',
description: 'Post Three Description'
}
]
/* Routes */
// 1.0 - page to display All Blog Posts Available
app.get('/blog', async(req, res) => {
// using just NodeJS won't enable use to render a page and send data together when rendering (in my knowledge)
// so the only way to do it, its just render a static html page for now
// - using 'path resolve' to get the path of where 'blog.html' situated
let parentPath = path.resolve(__dirname + '/blog.html', '../')
// - using 'sendFile' to render a static html page of 'blog.html'
res.sendFile(path.join(parentPath + '/views/blog.html'))
})
// 1.1 - route to handle passing of All Blog Posts Available
app.get('/api/blog', async(req, res) => {
try {
// send All Blog Posts Available
res.json({ message: 'Successful!', data: posts })
} catch(err) {
res.json({ message: 'Unsuccessful!', data: err })
}
})
// 2.0 - page to display Single Blog Post
app.get('/blog/:id', async(req, res) => {
// send user according to which Single Blog Post they clicked on
// - send user to Single Blog Post of 'id = 1'
if(+req.params.id === 1) {
// - using 'path resolve' to get the path of where 'singleBlog1.html' situated
let parentPath = path.resolve(__dirname + '/singleBlog1.html', '../')
// - using 'sendFile' to render a static html page of 'singleBlog1.html'
res.sendFile(path.join(parentPath + '/views/singleBlog1.html'))
} else if(+req.params.id === 2) { // - send user to Single Blog Post of 'id = 2'
// - using 'path resolve' to get the path of where 'singleBlog2.html' situated
let parentPath = path.resolve(__dirname + '/singleBlog2.html', '../')
// - using 'sendFile' to render a static html page of 'singleBlog2.html'
res.sendFile(path.join(parentPath + '/views/singleBlog2.html'))
} else if(+req.params.id === 3) { // - send user to Single Blog Post of 'id = 3'
// - using 'path resolve' to get the path of where 'singleBlog3.html' situated
let parentPath = path.resolve(__dirname + '/singleBlog3.html', '../')
// - using 'sendFile' to render a static html page of 'singleBlog3.html'
res.sendFile(path.join(parentPath + '/views/singleBlog3.html'))
} else {
// console log error message
console.log(`There's no post with the id of ${req.params.id} exist in our database.`)
}
})
/* Server Connection */
app.listen(5000, console.log('Server is up and running at port 5000.'))
Like shown above, we have no way of doing this dynamically. Unfortunately we have to create a different single blog post page for each and every of our post or new added post in the future. But, the problems still not end there yet tho. Continue on below:-
singleBlog1.html
(Page to display Single Blog Post of ID = 1):-<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blog</title>
</head>
<body>
<div class="container"></div>
<script src="/js/singleBlog1.js"></script>
</body>
</html>
singleBlog1.js
(Script to handle fetching of Single Blog Post of ID = 1);-// create a function to handle data fetching
let dataFromDB = async() => {
// fetch data (All Blog Posts Available) through API URL of '/api/blog/1'
const res = await fetch('/api/blog/1')
const json = await res.json()
if(json.message === 'Successful!') {
// update into UI
let posts, htmlTemplate
post = json.data
htmlTemplate = `
<div class="post" id="post-${post.id}">
<h1 class="title">${post.title}</h1>
<p class="desc">${post.description}</p>
</div>
`
// append the template to UI
document.querySelector('.container').insertAdjacentHTML('beforeend', htmlTemplate)
} else {
alert('No data fetched from db!')
}
}
dataFromDB()
With the example above, this also means that we need a separate JavaScript scripting for each singleBlog.html
we've created. And in our index.js
, we need to add one new route
to handle the sending of data to each singleBlog.js
we've created like shown below:-
index.js
:-/* Dependencies */
// Express Package
const express = require('express')
const app = express()
// Cors
const cors = require('cors')
// Path
const path = require('path')
/* Middlewares */
// cors
app.use(cors())
// body parser
app.use(express.json())
// Static folder
app.use(express.static('web'))
/* Gimmick Data Storage */
let posts = [
{
id: 1,
title: 'Post 1',
description: 'Post One Description'
},
{
id: 2,
title: 'Post 2',
description: 'Post Two Description'
},
{
id: 3,
title: 'Post 3',
description: 'Post Three Description'
}
]
/* Routes */
// 1.0 - page to display All Blog Posts Available
app.get('/blog', async(req, res) => {
// using just NodeJS won't enable use to render a page and send data together when rendering (in my knowledge)
// so the only way to do it, its just render a static html page for now
// - using 'path resolve' to get the path of where 'blog.html' situated
let parentPath = path.resolve(__dirname + '/blog.html', '../')
// - using 'sendFile' to render a static html page of 'blog.html'
res.sendFile(path.join(parentPath + '/views/blog.html'))
})
// 1.1 - route to handle passing of All Blog Posts Available
app.get('/api/blog', async(req, res) => {
try {
// send All Blog Posts Available
res.json({ message: 'Successful!', data: posts })
} catch(err) {
res.json({ message: 'Unsuccessful!', data: err })
}
})
// 2.0 - page to display Single Blog Post
app.get('/blog/:id', async(req, res) => {
// send user according to which Single Blog Post they clicked on
// - send user to Single Blog Post of 'id = 1'
if(+req.params.id === 1) {
// - using 'path resolve' to get the path of where 'singleBlog1.html' situated
let parentPath = path.resolve(__dirname + '/singleBlog1.html', '../')
// - using 'sendFile' to render a static html page of 'singleBlog1.html'
res.sendFile(path.join(parentPath + '/views/singleBlog1.html'))
} else if(+req.params.id === 2) { // - send user to Single Blog Post of 'id = 2'
// - using 'path resolve' to get the path of where 'singleBlog2.html' situated
let parentPath = path.resolve(__dirname + '/singleBlog2.html', '../')
// - using 'sendFile' to render a static html page of 'singleBlog2.html'
res.sendFile(path.join(parentPath + '/views/singleBlog2.html'))
} else if(+req.params.id === 3) { // - send user to Single Blog Post of 'id = 3'
// - using 'path resolve' to get the path of where 'singleBlog3.html' situated
let parentPath = path.resolve(__dirname + '/singleBlog3.html', '../')
// - using 'sendFile' to render a static html page of 'singleBlog3.html'
res.sendFile(path.join(parentPath + '/views/singleBlog3.html'))
} else {
// console log error message
console.log(`There's no post with the id of ${req.params.id} exist in our database.`)
}
})
// 2.1 - route to handle passing of Single Blog Post user requested
app.get('/api/blog/:id', async(req, res) => {
// send user Single Post data according to which user have requested
try {
// - send user Single Blog Post data of 'id = 1'
if(+req.params.id === 1) {
res.json({ message: 'Successful!', data: posts[0] })
} else if(+req.params.id === 2) { // - send user Single Blog Post data of 'id = 2'
res.json({ message: 'Successful!', data: posts[1] })
} else if(+req.params.id === 3) { // - send user Single Blog Post data of 'id = 3'
res.json({ message: 'Successful!', data: posts[2] })
} else {
// console log error message
console.log(`There's no post with the id of ${req.params.id} exist in our database.`)
}
} catch(err) {
// - send user Single Blog Post's error message
res.json({ message: 'Unsuccessful!', data: err })
}
})
/* Server Connection */
app.listen(5000, console.log('Server is up and running at port 5000.'))
Like I said earlier, this is the only way to do it now when just using bare Node JS. But don't worry tho. I'm going to show you how we can change our code, not much, just a tad actually, with just using a package called EJS (Embedded JavaScript Templating). Let's get started.
index.js
:-/* Dependencies */
// Express Package
const express = require('express')
const app = express()
// Cors
const cors = require('cors')
// Path
const path = require('path')
/* Middlewares */
// cors
app.use(cors())
// body parser
app.use(express.json())
// Static folder
app.use(express.static('web'))
/* Gimmick Data Storage */
let posts = [
{
id: 1,
title: 'Post 1',
description: 'Post One Description'
},
{
id: 2,
title: 'Post 2',
description: 'Post Two Description'
},
{
id: 3,
title: 'Post 3',
description: 'Post Three Description'
}
]
/* Routes */
// 1.0 - page to display & data to send of All Blog Posts Available
app.get('/blog', async(req, res) => {
// dynamically render a page while in the same time send data together with it
// - make sure to change your extension of 'blog.html' to 'blog.ejs' in order to make it work
try {
res.render('blog', { message: 'Successful!', data: posts })
} catch(err) {
res.render('blog', { message: 'Unsuccessful!', data: err })
}
})
// 2.0 - page to display & data to send of Single Blog Post
app.get('/blog/:id', async(req, res) => {
// filter which sigle post to send to singleBlog page
let post = posts.filter(post => post.id === +req.params.id)
// dynamically render a page while in the same time send data together with it
// - make sure to change your extension of 'singleBlog.html' to 'singleBlog.ejs' in order to make it work
try {
res.render('singleBlog', { message: 'Successful!', data: post })
} catch(err) {
res.render('singleBlog', { message: 'Unsuccessful!', data: err })
}
})
/* Server Connection */
app.listen(5000, console.log('Server is up and running at port 5000.'))
blog.ejs
:-<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blog</title>
</head>
<body>
<div class="container">
<% data.forEach(post => { %>
<div class="post" id="post-<%= post.id %>">
<h1 class="title"><%= post.title %></h1>
<p class="desc"><%= post.description %></p>
/* will bring user to route of '/blog/id' */
<a href="/blog/<%= post.id %>">Read More</a>
</div>
<% }) %>
</div>
</body>
</html>
singleBlog.ejs
(Previously as singleBlog1.html
or singleBlog2.html
or so forth):-<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Blog</title>
</head>
<body>
<div class="container">
<% data.forEach(post => { %>
<div class="post" id="post-<%= post.id %>">
<h1 class="title"><%= post.title %></h1>
<p class="desc"><%= post.description %></p>
</div>
<% }) %>
</div>
</body>
</html>
Ain't that more simple? With this we able to cut our code with only having:-
index.js
singleBlog.ejs
There you have it. We are able to overcome our problems of manually create every single blog post page that available with just using a template. When I just started learning to code using Node JS. Like I said earlier, I thought I could do it even without having to use any third party packages. But after a while learning and implement all sort of codes to build or make my own website (Portfolio). I started knowing that at some point, I need to use any third party packages to make my Portfolio to work as intended. And soon definitely without a doubt, I need to learn how to use a front-end framework too.
So guys, I hope what I share with you guys today able to at least help you to understand Node JS and the use of templating much better. This does not means that you should not learn Vanilla JavaScript and can straightaway learn how to use Front-end Framework. It depends actually. But, my recommendation will be to start learning the basic stuff first and progress more along the way. Create a website of your own. You will not believe how much and how fast you keep learning new stuff when doing so. It's the most effective way for me, personally.
Anyway, like always, thanks for being here. until next time. Chao! Salam.