Bookstore Ecommerce App using MEAN Stack
Last Updated :
08 May, 2024
In this article, we will build a simple yet powerful bookstore application using Angular for the front end and Node.js for the back end. This project application will showcase how to set up a full-stack web application where users can view, filter, and purchase various books.
Project Preview:

Prerequisites
Approach
We will follow a modular approach, separating the frontend and backend components. The frontend will communicate with the backend through HTTP requests to fetch book data and manage the cart.
- Display a list of books with their details like title, author, description, and price.
- Users can add books to their cart and remove them.
- The cart will display the total price and allow users to proceed to checkout.
- Implement filtering and sorting options for better user experience.
Steps to Create Application
Step 1: Create server folder and navigate to server
mkdir bookstore-backend
cd bookstore-backend
Step 2: Initialize the Node Application
npm init -y
Folder Structure(Backend)
Backend Folder Strucure
Step 3: Install the required dependencies.
npm install express mongoose cors body-parser
Updated dependencies looks like
"dependencies": {
"cors": "^2.8.5",
"express": "^4.19.2",
"mongoose": "^8.3.2"
}
Example: Create few file server.js,Book.js,data.jsonbookRoutes.js with following code given below:
JavaScript
//index.js
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const Book = require('./Book');
const bookRoutes = require('./bookRoutes');
const app = express();
const PORT = process.env.PORT || 5000;
// Middleware
app.use(express.json());
app.use(cors());
// MongoDB connection
mongoose.connect('Your mongo DB link',
{ useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB connected'))
.catch(err => console.error(err));
// Seed the database on server startup
const seedDatabase = async () => {
try {
await Book.deleteMany();
const books = require('./data.json');
await Book.insertMany(books);
console.log('Database seeded successfully');
} catch (error) {
console.error('Error seeding database:', error);
}
};
seedDatabase();
// Routes
app.use('/api/books', bookRoutes);
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
JavaScript
//book.js
const mongoose = require('mongoose');
const bookSchema = new mongoose.Schema({
title: String,
author: String,
genre: String,
description: String,
price: Number,
image: String
});
const Book = mongoose.model('Book', bookSchema);
module.exports = Book;
JavaScript
//bookRoutes.js
const express = require('express');
const Book = require('./Book');
const router = express.Router();
router.get('/', async (req, res) => {
try {
const allBooks = await Book.find();
res.json(allBooks);
} catch (error) {
console.error(error);
res.status(500)
.json({ error: 'Internal Server Error' });
}
});
module.exports = router;
JavaScript
//data.json
[
{
"title": "The Great Gatsby",
"author": "F. Scott Fitzgerald",
"genre": "Fiction",
"description": "A classic novel about the American Dream",
"price": 20,
"image": "https://media.geeksforgeeks.org/wp-content/
uploads/20240110011815/sutterlin-1362879_640-(1).jpg"
},
{
"title": "To Kill a Mockingbird",
"author": "Harper Lee",
"genre": "Fiction",
"description": "A powerful story of racial injustice and moral growth",
"price": 15,
"image": "https://media.geeksforgeeks.org/wp-content/
uploads/20240110011854/reading-925589_640.jpg"
},
{
"title": "1984",
"author": "George Orwell",
"genre": "Dystopian",
"description": "A dystopian vision of a totalitarian future society",
"price": 255,
"image": "https://media.geeksforgeeks.org/wp-content/
uploads/20240110011929/glasses-1052010_640.jpg"
},
{
"title": "The Great Gatsby",
"author": "F. Scott Fitzgerald",
"genre": "Fiction",
"description": "A classic novel about the American Dream",
"price": 220,
"image": "https://media.geeksforgeeks.org/wp-content/
uploads/20240110011929/glasses-1052010_640.jpg"
},
{
"title": "To Kill a Mockingbird",
"author": "Harper Lee",
"genre": "Fiction",
"description": "A powerful story of racial injustice and moral growth",
"price": 1115,
"image": "https://media.geeksforgeeks.org/wp-content/
uploads/20240110011929/glasses-1052010_640.jpg"
},
{
"title": "1984",
"author": "George Orwell",
"genre": "Dystopian",
"description": "A dystopian vision of a totalitarian future society",
"price": 125,
"image": "https://media.geeksforgeeks.org/wp-content/
uploads/20240110011929/glasses-1052010_640.jpg"
}
]
Start the server using the following command
node index.js
Step 4: Install Angular CLI (if not already installed)
npm install -g @angular/cli
Step 5: Create a new Angular project
ng new client --style=css --routing=false
cd client
Project Structure(Frontend)
Frontend Folder Structure
Dependencies
"dependencies": {
"@angular/animations": "^17.3.0",
"@angular/common": "^17.3.0",
"@angular/compiler": "^17.3.0",
"@angular/core": "^17.3.0",
"@angular/forms": "^17.3.0",
"@angular/platform-browser": "^17.3.0",
"@angular/platform-browser-dynamic": "^17.3.0",
"@angular/router": "^17.3.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
}
Change and update the files
- create 3 folders insider src/app :components,models and services
- Create files header-product.component.ts and header-product.component.css insider component folder
- Create file book.model.ts inside models folder
- Create file header-cart.service.ts inside services
- create app.module.ts inside app folder
- update code of app.component.ts,main.ts and index.html of app folder
HTML
<!-- src/index.html -->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bookstore</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
CSS
/* components/header-product.component.css */
/* Header Styles */
.navbar {
text-align: center;
background-color: #2c3e50;
color: white;
padding: 20px 0;
}
.navbar-item {
font-size: 24px;
font-weight: bold;
}
.header {
background-color: #34495e;
color: #fff;
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.cart {
position: relative;
cursor: pointer;
}
.cart span {
margin-right: 5px;
}
.cart-items {
position: absolute;
top: calc(100% + 5px);
right: 0;
background-color: #2c3e50;
border: 1px solid #34495e;
padding: 10px;
display: flex;
flex-direction: column;
}
.cart-items p {
margin: 5px 0;
}
/* Product List Styles */
.product-list {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
padding: 20px 0;
}
.product-card {
width: 30%;
margin-bottom: 20px;
background-color: #ecf0f1;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.product-card img {
width: 100%;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
}
.product-card:hover {
transform: translateY(-5px);
}
.product-details {
padding: 15px;
}
.product-details h3 {
margin-top: 0;
font-size: 20px;
}
.product-details p {
margin: 5px 0;
}
.product-details button {
background-color: #2ecc71;
color: #fff;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
.product-details button:hover {
background-color: #27ae60;
}
JavaScript
//components/header-product.component.ts
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { HeaderCartService } from '../services/header-cart.service';
import { Book } from '../models/book.model';
@Component({
selector: 'app-header-product',
template: `
<nav class="navbar">
<div class="navbar-brand">
<span class="navbar-item">
GFG Bookstore by Ashish Regmi</span>
</div>
</nav>
<!-- Header template -->
<div class="header">
<!-- Filter and Sort options -->
<div class="options">
<div class="filter-options">
<label for="minPrice">Min Price:</label>
<input type="number" id="minPrice"
[(ngModel)]="minPrice">
<label for="maxPrice">Max Price:</label>
<input type="number" id="maxPrice"
[(ngModel)]="maxPrice">
<button (click)="filterProducts()">Filter</button>
<label for="sort">Sort by:</label>
<select id="sort" [(ngModel)]="sortBy"
(change)="sortProducts()">
<option value="priceLowToHigh">
Price: Low to High</option>
<option value="priceHighToLow">
Price: High to Low</option>
</select>
</div>
</div>
<!-- Cart -->
<div class="cart" (click)="toggleCart() ">
<span>Cart ({{ cartItems.length }})</span>
<div *ngIf="showCart" class="cart-items"
(click)="preventClose($event)">
<div *ngFor="let item of cartItems">
<p>{{ item.title }} - {{ item.price }}</p>
<button (click)="removeFromCart(item)">Remove</button>
</div>
<div>Total Price: {{ calculateTotalPrice() }}</div>
</div>
</div>
</div>
<!-- Product list template -->
<div class="product-list">
<div *ngFor="let product of filteredProducts" class="product-card">
<img [src]="product.image" alt="Book Cover">
<div class="product-details">
<h3>{{ product.title }}</h3>
<p>{{ product.description }}</p>
<p>Price: {{ product.price }} Rs</p>
<button (click)="addToCart(product)">Add to Cart</button>
</div>
</div>
</div>
`,
styleUrls: ['./header-product.component.css']
})
export class HeaderProductComponent implements OnInit {
products: Book[] = [];
cartItems: Book[] = [];
showCart: boolean = false;
totalPrice: number = 0;
minPrice: number = 0;
maxPrice: number = 0;
filteredProducts: Book[] = [];
sortBy: string = 'priceLowToHigh';
constructor(private http: HttpClient,
private cartService: HeaderCartService) { }
ngOnInit(): void {
// Fetch products from the backend
this.http.get<Book[]>('http://localhost:5000/api/books')
.subscribe(products => {
this.products = products;
this.filteredProducts = products;
});
// Subscribe to changes in the cart
this.cartService.cart$.subscribe(cartItems => {
this.cartItems = cartItems;
});
}
addToCart(product: Book) {
this.cartService.addToCart(product);
this.calculateTotalPrice();
}
removeFromCart(product: Book) {
this.cartService.removeFromCart(product);
this.calculateTotalPrice();
}
toggleCart() {
this.showCart = !this.showCart;
}
calculateTotalPrice(): number {
return this.cartItems.reduce((total, item) =>
total + item.price, 0);
}
filterProducts() {
this.filteredProducts = this.products.filter(product => {
return product.price >= this.minPrice &&
product.price <= this.maxPrice;
});
this.sortProducts();
}
sortProducts() {
if (this.sortBy === 'priceLowToHigh') {
this.filteredProducts.sort((a, b) => a.price - b.price);
} else if (this.sortBy === 'priceHighToLow') {
this.filteredProducts.sort((a, b) => b.price - a.price);
}
}
preventClose(event: MouseEvent) {
event.stopPropagation();
}
}
JavaScript
// models/book.model.ts
export interface Book {
_id: string;
title: string;
author: string;
genre: string;
description: string;
price: number;
image: string;
}
JavaScript
// services/header-cart.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { Book } from '../models/book.model';
@Injectable({
providedIn: 'root'
})
export class HeaderCartService {
private cart: Book[] = [];
private cartSubject = new BehaviorSubject
<Book[]>(this.cart);
cart$ = this.cartSubject.asObservable();
constructor(private http: HttpClient) { }
addToCart(book: Book) {
this.cart.push(book);
this.cartSubject.next(this.cart);
}
removeFromCart(book: Book) {
const index = this.cart.findIndex
(item => item._id === book._id);
if (index !== -1) {
this.cart.splice(index, 1);
this.cartSubject.next(this.cart);
}
}
}
JavaScript
// client/src/app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<app-header-product></app-header-product>
`,
})
export class AppComponent { }
JavaScript
// src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { HeaderProductComponent } from './components/header-product.component';
import { HeaderCartService } from './services/header-cart.service';
@NgModule({
declarations: [
AppComponent,
HeaderProductComponent
],
imports: [
BrowserModule,
FormsModule, // Add FormsModule here
HttpClientModule
],
providers: [HeaderCartService],
bootstrap: [AppComponent]
})
export class AppModule { }
JavaScript
// client/src/main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
Start the Angular App using the following command.
ng serve
Output

Similar Reads
Bookstore Ecommerce App using MERN Stack Bookstore E-commerce project is a great way to showcase your understanding of full-stack development. In this article, we'll walk through the step-by-step process of creating a Bookstore E-commerce using the MERN (MongoDB, Express.js, React, Node.js) stack. This project will showcase how to set up a
8 min read
Notes Maker App using MEAN Stack The Notes Maker project is a helpful web application designed to help users effectively create, manage, and organize their notes. In this article we are utilizing the MEAN (MongoDB, Express, Angular, Node) Stack, to build a notes maker application that provides a seamless user experience for note-ta
7 min read
Notes Maker App using MERN Stack The "Notes Maker" project is an helpful web application designed to help users effectively create, manage, and organize their notes. In this article we are utilizing the MERN (MongoDB, Express, React, Node) Stack, to build a notes maker application that provides a seamless user experience for note-t
6 min read
Community Marketplace App using MERN Stack Building a community Marketplace App will help you understand the foundational concepts of full-stack development using the MERN(MongoDB, ExpressJS, React, NodeJS) stack. This tutorial will guide you to set up the backend server for the project and demonstrate the integration of frontend functionali
6 min read
Restaurant App using MERN Stack Creating a Restaurant app will cover a lot of features of the MERN stack. In this tutorial, we'll guide you through the process of creating a restaurant application using the MERN stack. The application will allow users to browse through a list of restaurants, view their menus, and add items to a sh
11 min read