Learn step-by-step to create a MVC application using Express.js-(MVC Series-2)

Simmy
6 min readJul 28, 2022

--

Photo by Glenn Carstens-Peters on Unsplash

This is a Continuation of Express-MVC Series-1.In This article we will be creating a sign up page for the application and its related User Model ,View and related sign up Route.

USER MODEL,VIEW AND CONTROLLER

USER MODEL

  1. Create model folder -This will hold the sequelize model and definition for the columns in the tables.

User should be able to sign up to the tech blog site using an email address and password.So User table should have an email column, password column and user id column(created by default).

  • Create an index.js file -This is where the relationship between the models will be defined also exports all the models.(any require(/model) will be referring to the index file in it by default)

NOTE:Once all the models are created we will update index file with the relation

//Import model definition from respective model filesconst User=require('./User');//Export the modelsmodule.exports=User;
  • Create a User.js file -This is where the name of the table ‘user’, columns and their data types will be defined.
  • Sequelize use Model class which represent a table in a database and all the tables models used in the application will inherit from Model.
//Import the Model class from sequelize to define the tables of the applicationconst { Model, DataTypes } = require('sequelize');//Import the sequelize instance from connection fileconst sequelize=require('../config/connection.js');//Import bcrypt package to hash the dataconst bcrypt = require('bcrypt');/*
User model extends from the Model class of sequelize package
Sequelize allows to define instance methods on your model class which could be called on the model data
checkPassword is used to compare the password entered by the user and that saved in the table(This will be invoked in the routes)
*/
class User extends Model {checkPassword(loginPw) {
return bcrypt.compareSync(loginPw, this.password);
}
}
/*
Column data is passed as a nested object.init method is used to define the User model and its attributes
Datatypes class allows to define the data typesColumn in user tables are* id - id column will be created by default- Datatypes.Integer will hold only numerical value- autoincrement:true will increment the values by 1- primaryKey:true will set the column as primary key of the table-allowNull:false ensure the column
* email -This will be the column that will hold email data-Datatype will be string-unique:true ensure the column will hold unique data-allowNull:true ensure column contains data
* password -This will be the column that will hold password-Datatype will be string-allowNull:true ensure column contains data-validate: adds inbuilt validation options to the colum data-Validates len:[8] validate password data is of minimum of length 8-Syntax : validate:{len:[min,max]} ,if only one argument given that will be the min value
Sequelize allows to pass hooks as second optional argument.hooks can be defined to perform any before or after operation on data.
In this case we define a beforeCreate hook which will use bcrypt package to hash(using hash method) the password before saving it to the password column where newUserdata will be an object with user data containing id, email and password and this function is execute before create operation on the user tableThis newUserdata will be either from seed file or data passed by routes when a new user sign up* sequelize instance (imported from connection) is also passed along with hooks as second argumenttimestamps: false //This will remove the default timestamp columns(created and updated) from the tablefreezeTableName: true, //By default pluralize the table name,ex 'users' to prevent this freezeTableName should be trueunderscored: true, //This will ensure any columns specified in camel case will be converted to underscore column name formatmodelName: "user", //pass the table name as 'user'*/User.init(
{
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey:true,
autoIncrement: true,
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [8],
},
},
},{
hooks: {
beforeCreate: async(newUserData) => {
newUserData.password = await bcrypt.hash(newUserData.password, 10);
return newUserData;
},
},
sequelize,
timestamps: false,
freezeTableName: true,
underscored: true,
modelName: "user",
});
//Export the user model
module.exports = User;

USER VIEW

2) Create views folder -This will hold the handlebar code for the UI related to user model like the sign up page, login, logout pages

Create views folder >inside that a layouts folder >inside that create file main.handlebars inside main.handlebars

Lets add a basic skeleton(using html, bootstrap) for the tech blog main page and signup page handlebars.

Below handlebars will create a page with navigation bar and links to Home,Dashboard,Logout pages

main.handlebars

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tech Blog Site</title>
<!--Google Font Link-->
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,500;1,300&display=swap" rel="stylesheet">
<!-- Bootstrap Link -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,400;0,500;1,300&family=Splash&display=swap" rel="stylesheet"><!--Font Awesome Icon-->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!--Custom Style sheet from public folder-->
<link rel="stylesheet" href="/css/style.css"/>
</head>
<body>
<nav class="container-fluid d-flex flex-column align-items-start flex-wrap">
<div class="d-flex justify-content-start py-2">
<a href="/home">Home</a>
<a href="/dashboard">Dashboard</a>
<a href="/login" id="login">Login</a>
<a href="/logout" id="logout">Logout</a>
</div>
<h4>The Tech Blog</h4>
</nav>
<main class="d-flex flex-column px-3 py-3">
{{{body}}}
</main>
<!--Bootstrap JS Link--><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script></body>

Below handlebars will create a signup page with signup form with username, email and sign up button.And signup.js script is linked to the page which will handle the form submission event.

signup.handlebars

<div class="container my-5 d-flex flex-column py-3 align-items-center" id="login-container"><h6 class="my-3">SIGNUP</h6>
<form class="container d-flex flex-column align-items-center" id="signup-form">
<div class="form-group my-3 "><label for="username" class="my-2">Username</label>
<input type="text" class="form-control px-5" id="signup-username" placeholder="Enter Username">
</div><div class="form-group my-4"><label for="password" class="my-2">Password</label>
<input type="text" class="form-control px-5" id="signup-password" placeholder="Enter Password">
</div><div class="form-group my-3">
<button class="btn px-4" id="signup-btn">SignUp</button>
</div>
<p class="error-message text-danger"></p>
</form>
</div>
<script src="/js/signup.js"></script>

USER ROUTES/CONTROLLER

3) Create controller folder -This will hold all the route related to the user model.We will create a sign up route that will render the sign up form page.

Create an index.js file in the controller folder to define the sign up route.

This will tell the application that when a user enter http://localhost:3002/signup (domain/port/routepath) in browser it should render the signup.handlebars

index.js

//Import the express router package to define the routes for applicationconst router = require("express").Router();//Import the User model from index file in modelsconst User=require('../models');//SIGN UP ROUTErouter.get("/signup", async (req, res) => {
res.render("signup");
});module.exports=router;
  • public folder — This will hold the CSS and JS script code for the UI.
  • Create a js folder inside the public folder and add a new file script.js. We will later defining the event handler for sign up form in this file.
  • Create a css folder inside the public folder and add a new file styles.css. Add basic styling for the signup.handlebars and main.handlebars page
*{margin:0;
padding: 0;
box-sizing: border-box;
}a,a:hover,a:link,a:visited{
color:var(--nav-color);
text-decoration: none;
}
:root{
--body-color:#e8d5b7;
--text-color:#0e2431;
--link-color:#f9b248;
--secondary-color:#fc3a52;
--nav-color:#0e2431;
}
body{
background-color: #fff;
color: var(--text-color);
}
nav{
height:30%;
background-color: var(--nav-color);
padding:2rem;
}
nav a{
padding: 0 2rem;
color: #fff !important;
}
h4{
background-color: var(--body-color);
border-radius: 0.3rem;
margin-left:2rem;
margin-top:2rem;
padding:0.2rem 0.5rem;
}
/*Styling Sign Up Form*/#signup-form{
background-color: var(--link-color);
border-radius: 1rem;
width:50%;
}
.btn{
background-color:var(--nav-color);
color: var(--body-color);
}
  • seeds folder -This will hold the test data and sequelize code to insert the data to the tables.We will create a user.json file with following test data

user.json

[{
"username":"sai12345",
"password": "password12345"
},
{
"username": "Lernantino",
"password": "password12345"
},
{
"username": "Amiko",
"password": "password12345"
}]

This is how now the folder Structure should look like

Now lets test the route /signup is rendering the signup page by running the server using the command node server.js. After starting the server enter http:localhost:3002/signup in browser to view the signup page

Sign Up Page

Next Article will be covering the front end sign up validation and submission of the form as well as login page.

--

--

Simmy

An Evolving Full Stack Developer | Passionate about Creating websites and Mastering the new Technologies of Full Stack Development