Open In App

Address Book using MEAN

It is important to have an efficient way to manage contacts for personal and professional life. Building an address book application can be a rewarding project, allowing you to learn the ins and outs of full-stack web development while creating a useful tool. In this article, we'll explore how to build an address book application using the MEAN stack, comprising MongoDB, Express.js, Angular, and Node.js.

Project Preview:

preview image of address book using mean

PREVIEW IMAGE FOR CREATE ADDRESS

Prerequisites:

Approach to Create Address Book using MEAN Stack

Backend:

Frontend:

Steps to Create Project

Step 1: Create the main folder for complete project

mkdir address-book
cd address-book

Step 2: Initialize the node.js project

npm init -y

Step 3: Install the required dependencies

npm install express mongoose jsonwebtoken bcryptjs nodemon cors body-parser

Folder Structure (Backend):

Screenshot-2024-04-15-080820

PROJECT STRUCTURE IMAGE FOR BACKEND

The updated dependencies in package.json file of backend will look like:

"dependencies": {
"@auth0/angular-jwt": "^5.2.0",
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"express": "^4.19.2",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.3.0",
"nodemon": "^3.1.0"
}

Example: Create the required files as seen on the project structure and add the following codes.

// controller/addressController.js

const Address = require("../model/Address");
const jwt = require("jsonwebtoken");
const secretKey = "jwtSecret";

exports.getAllAddress = async (req, res) => {
    let userId;
    try {
        jwt.verify(
            req.headers["authorization"].substring(7),
            secretKey,
            (error, decodedToken) => {
                if (error) {
                    res.status(401).json({
                        success: false,
                        message: error.message,
                    });
                } else {
                    userId = decodedToken.user.id;
                }
            }
        );
        const addresses = await Address.find();
        res.status(200).json(addresses);
    } catch (error) {
        res.status(500).json({
            success: false,
            message: error.message,
        });
    }
};

exports.getAddressById = async (req, res) => {
    try {
        const id = req.params.id;
        const address = await Address.findById(id);
        res.status(200).json(address);
    } catch (error) {
        res.status(500).json({
            success: false,
            message: error.message,
        });
    }
};

exports.createAddress = async (req, res) => {
    try {
        let address = {};
        const {
            firstname,
            lastname,
            email,
            phone,
            addressline,
            state,
            pincode,
            country,
            dob,
        } = req.body;
        if (
            req.headers["authorization"] &&
            req.headers["authorization"].startsWith("Bearer ")
        ) {
            jwt.verify(
                req.headers["authorization"].substring(7),
                secretKey,
                (error, decodedToken) => {
                    if (error) {
                        res.status(401).json({
                            success: false,
                            message: error.message,
                        });
                    } else {
                        address = new Address({
                            user: decodedToken.user.id,
                            firstname,
                            lastname,
                            email,
                            phone,
                            addressline,
                            state,
                            pincode,
                            country,
                            dob,
                        });
                    }
                }
            );
            await address.save();
            res.status(200).json({
                success: true,
                address: address,
            });
        }
    } catch (error) {
        res.status(500).json({
            success: false,
            message: error.message,
        });
    }
};

exports.updateAddress = async (req, res) => {
    try {
        const { id } = req.params;
        const {
            firstname,
            lastname,
            email,
            phone,
            addressline,
            state,
            pincode,
            country,
            dob,
        } = req.body;
        const address = await Address.findByIdAndUpdate(
            id,
            {
                firstname,
                lastname,
                email,
                phone,
                addressline,
                state,
                pincode,
                country,
                dob,
            },
            { new: true }
        );
        res.status(201).json({
            success: true,
            address: address,
        });
    } catch (error) {
        res.status(500).json({
            success: false,
            message: error.message,
        });
    }
};

exports.deleteAddress = async (req, res) => {
    try {
        const { id } = req.params;
        await Address.findByIdAndDelete(id);
        res.status(200).json({
            success: true,
            message: "Address Deleted Successfully",
        });
    } catch (error) {
        res.status(500).json({
            success: false,
            message: "Error while deleting address",
        });
    }
};
// controller/authController.js

const User = require("../model/User");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");

exports.register = async (req, res) => {
    try {
        const { username, email, password } = req.body;
        let user = await User.findOne({ email });
        if (user) {
            return res.status(400).json({
                message: "User Already Exist",
                success: false,
            });
        }
        user = new User({
            username: username,
            email: email,
            password: password,
        });
        const salt = await bcrypt.genSalt(10);
        user.password = await bcrypt.hash(password, salt);
        await user.save();
        const token = generateJwtToken(user.id);
        res.status(201).json({
            success: true,
            token: token,
            message: "User registered successfully",
        });
    } catch (error) {
        res.status(500).json({
            message: "Server error! New user registration failed",
            success: false,
        });
    }
};

exports.login = async (req, res) => {
    try {
        const { email, password } = req.body;
        const user = await User.findOne({ email });
        if (!user) {
            return res.status(400).json({
                message: "Invalid credentials",
                success: false,
            });
        }
        const isMatched = await bcrypt.compare(password, user.password);
        if (!isMatched) {
            return res.status(400).json({
                message: "Invalid credentials",
                success: false,
            });
        }
        const token = generateJwtToken(user.id);
        res.status(200).json({
            success: true,
            message: "User logged in successfully",
            token: token,
        });
    } catch (error) {
        return res.status(500).json({
            success: false,
            message: "Internal Server Error, Login unsuccessful",
        });
    }
};

function generateJwtToken(userID) {
    const payload = {
        user: {
            id: userID,
        },
    };
    return jwt.sign(payload, "jwtSecret", { expiresIn: 3600 });
}

exports.getUserDetailsFronUserId = async (req, res) => {
    try {
        const { id } = req.params;
        const user = await User.findById(id);
        return res.status(200).json(user);
    } catch (error) {
        res.status(500).json({
            success: false,
            message: error.message,
        });
    }
};
// model/Address.js

const mongoose = require('mongoose');

const addressSchema = new mongoose.Schema({
    user: {
        type: mongoose.Schema.ObjectId,
        ref: "User",
        required: true
    },
    firstname: {
        type: String,
        required: true
    },
    lastname: {
        type: String,
        required: true
    },
    email: {
        type: String,
        required: true
    },
    phone: {
        type: String,
        required: true
    },
    addressline: {
        type: String,
        required: true
    },
    state: {
        type: String,
        required: true
    },
    pincode: {
        type: String,
        required: true
    },
    country: {
        type: String,
        required: true
    },
    dob: {
        type: Date,
        required: true
    }
});

module.exports = mongoose.model('Address', addressSchema);
// model/User.js

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
    username: {
        type: String,
        required: true
    },
    email: {
        type: String,
        required: true,
        uniques: true
    },
    password: {
        type: String,
        required: true
    }
});

module.exports = mongoose.model('User', userSchema);
// route/addressRoutes.js

const express = require("express");
const router = express.Router();
const addressController = require("../controller/addressController");

router.get("/getAllAddress", addressController.getAllAddress);

router.get("/getAddressById/:id", addressController.getAddressById);

router.post("/createAddress", addressController.createAddress);

router.put("/updateAddress/:id", addressController.updateAddress);

router.delete("/deleteAddress/:id", addressController.deleteAddress);

module.exports = router;
//route/authRoutes.js

const express = require("express");
const router = express.Router();
const authController = require("../controller/authController");

router.post("/register", authController.register);

router.post("/login", authController.login);

router.get("/:id", authController.getUserDetailsFronUserId);

module.exports = router;
// server.js

const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const authRoutes = require("../backend/route/authRoutes");
const addressRoutes = require("../backend/route/addressRoutes");

const app = express();
app.use(cors());
app.use(express.json());

mongoose
    .connect("mongodb://localhost:27017/address-book", {
        family: 4,
    })
    .then(() => console.log("Mongo DB connected"))
    .catch((err) => console.log(err));

app.use("/api/auth", authRoutes);
app.use("/api/address", addressRoutes);

const PORT = 5000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));

Step 4: To start the backend run the following command.

nodemon server.js

Step 5: Install the angular CLI

npm install -g @angular/cli

Step 6: Create a new angular project

ng new frontend

Step 7: Create components for different functionalities in angular

Syntax - ng generate component <component-name>
ng generate component user
ng generate component address-create
ng generate component address

Step 8: Create services for communication between frontend and backend

Syntax - ng generate service <service-name>
ng generate service auth
ng generate service address
ng generate service shared

Folder Structure(Frontend):

Screenshot-2024-04-15-081600

PROJECT STRUCTURE FOR FRONTEND

The updated dependencies in package.json file of frontend will look like:

"dependencies": {
"@angular/animations": "^17.2.0",
"@angular/common": "^17.2.0",
"@angular/compiler": "^17.2.0",
"@angular/core": "^17.2.0",
"@angular/forms": "^17.2.0",
"@angular/platform-browser": "^17.2.0",
"@angular/platform-browser-dynamic": "^17.2.0",
"@angular/platform-server": "^17.2.0",
"@angular/router": "^17.2.0",
"@angular/ssr": "^17.2.3",
"@auth0/angular-jwt": "^5.2.0",
"express": "^4.18.2",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
}

Example: Create the required files as seen in project structure and add the following codes.

<!-- address.compoennt.html -->

<div class="container">
  <a class="link-button" (click)="showAddFormFunction()">Create New Address</a>
  <h2>List of Address</h2>
  <div
    *ngIf="displayedAddressList.length > 0; else noAddress"
    class="table-container"
  >
    <table class="address-table">
      <thead>
        <tr>
          <th>First Name</th>
          <th>Last Name</th>
          <th>Email ID</th>
          <th>Phone</th>
          <th>Address Line</th>
          <th>State</th>
          <th>PIN Code</th>
          <th>Country</th>
          <th>Date of Birth</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let address of displayedAddressList">
          <td>{{ address.firstname }}</td>
          <td>{{ address.lastname }}</td>
          <td>{{ address.email }}</td>
          <td>{{ address.phone }}</td>
          <td>{{ address.addressline }}</td>
          <td>{{ address.state }}</td>
          <td>{{ address.pincode }}</td>
          <td>{{ address.country }}</td>
          <td>{{ address.dob }}</td>
          <td>
            <button class="btn" (click)="getAddressById(address._id)">
              Get Adress
            </button>
            <button
              class="btn"
              (click)="populateUpdateForm(address)"
              *ngIf="address.user === getUserId()"
            >
              Update
            </button>
            <button
              class="btn delete-btn"
              (click)="confirmDelete(address._id)"
              *ngIf="address.user === getUserId()"
            >
              Delete
            </button>
          </td>
        </tr>
      </tbody>
    </table>
  </div>

  <ng-template #noAddress>
    <div class="no-address-container">
      <p>No Address Available</p>
    </div>
  </ng-template>

  <div *ngIf="showUpdateForm" class="update-form-container">
    <button class="close-button" (click)="cancelUpdate()">X</button>
    <h2>Update Address</h2>
    <form class="update-form" (ngSubmit)="updateAddress(addressUpdated._id)">
      <div>
        <label for="updateFirstName">First Name:</label>
        <input
          type="text"
          id="updateFirstName"
          name="updateFirstName"
          [(ngModel)]="addressUpdated.firstname"
          required
        />
      </div>
      <div>
        <label for="updateLastName">Last Name:</label>
        <input
          type="text"
          id="updateLastName"
          name="updateLastName"
          [(ngModel)]="addressUpdated.lastname"
          required
        />
      </div>
      <div>
        <label for="updateEmail">Email ID:</label>
        <input
          type="email"
          id="updateEmail"
          name="updateEmail"
          [(ngModel)]="addressUpdated.email"
          required
        />
      </div>
      <div>
        <label for="updatePhone">Phone Number:</label>
        <input
          type="number"
          id="updatePhone"
          name="updatePhone"
          [(ngModel)]="addressUpdated.phone"
          required
        />
      </div>
      <div>
        <label for="updateAddressLine">Address Line:</label>
        <input
          type="text"
          id="updateAddressLine"
          name="updateAddressLine"
          [(ngModel)]="addressUpdated.addressline"
          required
        />
      </div>
      <div>
        <label for="updateState">Address Line:</label>
        <input
          type="text"
          id="updateState"
          name="updateState"
          [(ngModel)]="addressUpdated.state"
          required
        />
      </div>
      <div>
        <label for="updatePincode">Address Line:</label>
        <input
          type="number"
          id="updatePincode"
          name="updatePincode"
          [(ngModel)]="addressUpdated.pincode"
          required
        />
      </div>
      <div>
        <label for="updateCountry">Address Line:</label>
        <input
          type="text"
          id="updateCountry"
          name="updateCountry"
          [(ngModel)]="addressUpdated.country"
          required
        />
      </div>
      <div>
        <label for="updateDOB">Date Of Birth:</label>
        <input
          type="date"
          id="updateDOB"
          name="updateDOB"
          [(ngModel)]="addressUpdated.dob"
          required
        />
      </div>
      <div>
        <button type="submit">Update Address</button>
        <button type="button" (click)="cancelUpdate()">Cancel</button>
      </div>
    </form>
  </div>

  <div
    *ngIf="!showUpdateForm && addressById._id"
    class="view-address-container"
  >
    <button class="close-button" (click)="closeView()">X</button>
    <h2>View Address</h2>
    <form class="view-address-form">
      <div>
        <label for="viewFirstName">First Name:</label>
        <input
          type="text"
          id="viewFirstName"
          name="viewFirstName"
          [(ngModel)]="addressById.firstname"
          required
        />
      </div>
      <div>
        <label for="viewLastName">Last Name:</label>
        <input
          type="text"
          id="viewLastName"
          name="viewLastName"
          [(ngModel)]="addressById.lastname"
          required
        />
      </div>
      <div>
        <label for="viewEmail">Email ID:</label>
        <input
          type="email"
          id="viewEmail"
          name="viewEmail"
          [(ngModel)]="addressById.email"
          required
        />
      </div>
      <div>
        <label for="viewPhone">Phone Number:</label>
        <input
          type="number"
          id="viewPhone"
          name="viewPhone"
          [(ngModel)]="addressById.phone"
          required
        />
      </div>
      <div>
        <label for="viewAddressLine">Address Line:</label>
        <input
          type="text"
          id="viewAddressLine"
          name="viewAddressLine"
          [(ngModel)]="addressById.addressline"
          required
        />
      </div>
      <div>
        <label for="viewState">State:</label>
        <input
          type="text"
          id="viewState"
          name="viewState"
          [(ngModel)]="addressById.state"
          required
        />
      </div>
      <div>
        <label for="viewPincode">PIN Code:</label>
        <input
          type="text"
          id="viewPincode"
          name="viewPincode"
          [(ngModel)]="addressById.pincode"
          required
        />
      </div>
      <div>
        <label for="viewCountry">Country:</label>
        <input
          type="text"
          id="viewCountry"
          name="viewCountry"
          [(ngModel)]="addressById.country"
          required
        />
      </div>
      <div>
        <label for="viewDOB">Date Of Birth:</label>
        <input
          type="date"
          id="viewDOB"
          name="viewDOB"
          [(ngModel)]="addressById.dob"
          required
        />
      </div>
      <div>
        <a href="/getAllAddress" class="link-button" (click)="closeView()"
          >Get All Address</a
        >
      </div>
    </form>
  </div>
</div>
<!-- address-create.compoentn.html -->

<div class="container">
  <div class="create-form-container">
    <h2>Create New Address</h2>
    <form class="create-form" (ngSubmit)="createAddress()">
      <div>
        <label for="firstName">First Name:</label>
        <input
          type="text"
          id="firstName"
          name="firstName"
          [(ngModel)]="addressCreated.firstname"
          required
        />
      </div>
      <div>
        <label for="lastName">Last Name:</label>
        <input
          type="text"
          id="lastName"
          name="lastName"
          [(ngModel)]="addressCreated.lastname"
          required
        />
      </div>
      <div>
        <label for="email">Email:</label>
        <input
          type="email"
          id="email"
          name="email"
          [(ngModel)]="addressCreated.email"
          required
        />
      </div>
      <div>
        <label for="phone">Phone:</label>
        <input
          type="number"
          id="phone"
          name="phone"
          [(ngModel)]="addressCreated.phone"
          required
        />
      </div>
      <div>
        <label for="addressLine">Address Line:</label>
        <input
          type="text"
          id="addressLine"
          name="addressLine"
          [(ngModel)]="addressCreated.addressline"
          required
        />
      </div>
      <div>
        <label for="state">State:</label>
        <input
          type="text"
          id="state"
          name="state"
          [(ngModel)]="addressCreated.state"
          required
        />
      </div>
      <div>
        <label for="pinCode">PIN Code:</label>
        <input
          type="number"
          id="pinCode"
          name="pinCode"
          [(ngModel)]="addressCreated.pincode"
          required
        />
      </div>
      <div>
        <label for="country">Country:</label>
        <input
          type="text"
          id="country"
          name="country"
          [(ngModel)]="addressCreated.country"
          required
        />
      </div>
      <div>
        <label for="dob">Date Of Birth:</label>
        <input
          type="date"
          id="dob"
          name="dob"
          [(ngModel)]="addressCreated.dob"
          required
        />
      </div>
      <div>
        <button type="submit">Add Address</button>
        <button type="button" (click)="resetForm()">Clear</button>
        <a href="/getAllAddress" class="link-button">Get All Address</a>
      </div>
    </form>
  </div>
</div>
<!-- user.component.hmtl -->

<div class="error-message" *ngIf="errorMessage">{{ errorMessage }}</div>
<div class="success-message" *ngIf="successMessage">{{ successMessage }}</div>

<div class="container" *ngIf="loginActive">
  <h2>Login</h2>
  <form (ngSubmit)="login()">
    <div class="form-group">
      <label for="email">Email:</label>
      <input
        type="email"
        class="form-control"
        id="email"
        name="email"
        [(ngModel)]="email"
        required
      />
    </div>
    <div class="form-group">
      <label for="password">Password:</label>
      <input
        type="password"
        class="form-control"
        id="password"
        name="password"
        [(ngModel)]="password"
        required
      />
    </div>
    <button type="submit" class="btn btn-primary">Login</button>
  </form>
</div>
<div class="container" *ngIf="registerActive">
  <h2>Register</h2>
  <form (submit)="register()">
    <div class="form-group">
      <label for="username">Username</label>
      <input
        type="text"
        id="username"
        class="form-control"
        [(ngModel)]="username"
        name="username"
        required
      />
    </div>
    <div class="form-group">
      <label for="email">Email</label>
      <input
        type="email"
        id="email"
        class="form-control"
        [(ngModel)]="email"
        name="email"
        required
      />
    </div>
    <div class="form-group">
      <label for="password">Password</label>
      <input
        type="password"
        id="password"
        class="form-control"
        [(ngModel)]="password"
        name="password"
        required
      />
    </div>
    <button type="submit" class="btn btn-primary">Register</button>
  </form>
</div>
<!-- app.component.html -->

<main class="main">
  <div class="content">
    <div class="left-side">
      <h1>{{ title }}</h1>
      <div>
        <ul>
          <li><a (click)="login()" *ngIf="!isLoggedIn">Login</a></li>
          <li><a (click)="register()" *ngIf="!isLoggedIn">Register</a></li>
          <li><a (click)="logout()" *ngIf="isLoggedIn">Logout</a></li>
        </ul>
      </div>
    </div>
  </div>
</main>
<router-outlet> </router-outlet>
/* app.component.css */

.main {
    display: flex;
    flex-direction: column;
    align-items: center;
    background-color: darkslategrey;
    color: white;
}

.content {
    width: 100%;
    max-width: 1200px;
    padding: 20px;
}

.left-side {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.left-side h1 {
    margin: 0;
    margin-left: 3%;
}

.left-side ul {
    list-style-type: none;
    padding: 0;
    margin: 0;
}

.left-side li {
    display: inline;
    margin-right: 20px;
}

.left-side li a {
    text-decoration: none;
    color: white;
    font-weight: bold;
    font-size: 1.5rem;
}

.left-side li a:hover {
    color: lightgray;
}

a {
    cursor: pointer;
}
/* address.component.css */

.container {
    max-width: 100%;
    margin: 0 auto;
    padding: 20px;
}

.address-table {
    width: 100%;
    border-collapse: collapse;
}

.address-table th,
.address-table td {
    padding: 10px;
    border: 1px solid #ccc;
    text-align: center;
}

h2 {
    text-align: center;
}

.address-table th {
    background-color: #f0f0f0;
}

.update-form-container,
.view-address-container {
    margin-top: 20px;
    padding: 20px;
    border: 1px solid #ccc;
}

.update-form,
.view-address-form {
    display: flex;
    flex-direction: column;
}

.update-form input,
.view-address-form input {
    margin-bottom: 10px;
}

.btn {
    padding: 8px 16px;
    margin-right: 10px;
    margin-bottom: 1.5vmax;
    cursor: pointer;
    background-color: #0056b3;
    color: #fff;
    border: none;
    border-radius: 4px;
}

.delete-btn {
    background-color: #dc3545;
}

.link-button {
    display: inline-block;
    padding: 8px 16px;
    background-color: #1b599a;
    color: #fff;
    text-decoration: none;
    border-radius: 4px;
    cursor: pointer;
}

.link-button-clear {
    display: inline-block;
    padding: 8px 16px;
    background-color: #dc3545;
    color: #fff;
    text-decoration: none;
    border-radius: 4px;
    cursor: pointer;
    border: none;
}

.no-address-container {
    margin-top: 20px;
    padding: 10px;
    background-color: #f8d7da;
    color: #721c24;
    border: 1px solid #f5c6cb;
    border-radius: 4px;
}

.no-address-container p {
    text-align: center;
    margin: 0;
}

/* Update Activity */

.update-form-container {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 90%;
    background-color: rgba(255, 255, 255, 1);
    padding: 3vmax;
    border-radius: 5px;
    overflow-y: auto;
}

.update-form-container h2 {
    text-align: center;
    font-size: 2rem;
}

.update-form-container .close-btn {
    position: absolute;
    top: 15px;
    right: 5px;
    font-size: 18px;
    color: #555;
    cursor: pointer;
}

.update-form-container .close-btn:hover {
    color: #333;
}

.update-form label {
    display: block;
    margin-bottom: 5px;
}

.update-form input[type="text"],
.update-form input[type="number"],
.update-form input[type="date"],
.update-form input[type="email"] {
    width: calc(100% - 12px);
    padding: 10px;
    margin-bottom: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
}

.update-form button[type="submit"],
.update-form button[type="button"] {
    width: 10%;
    padding: 10px;
    background-color: green;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    margin-right: 10px;
}

.update-form button[type="button"] {
    background-color: #dc3545;
}

.view-address-container {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 90%;
    background-color: rgba(255, 255, 255, 1);
    padding: 3vmax;
    border-radius: 5px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

.view-address-container h2 {
    text-align: center;
    font-size: 2rem;
}

.view-address-form label {
    display: block;
    margin-bottom: 5px;
}

.view-address-form input[type="text"],
.view-address-form input[type="number"],
.view-address-form input[type="date"],
.view-address-form input[type="email"] {
    width: calc(100% - 12px);
    padding: 10px;
    margin-bottom: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
}

.view-address-form button[type="submit"],
.view-address-form a {
    width: 10%;
    padding: 10px;
    background-color: #0056b3;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    text-align: center;
    display: inline-block;
    text-decoration: none;
}

.close-button {
    position: absolute;
    top: 20px;
    right: 10px;
    padding: 5px 10px;
    background-color: #ccc;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

.close-button:hover {
    background-color: #aaa;
}
/* address-create.component.css */

.container {
    max-width: 100%;
    margin: 0 auto;
    padding: 20px;
}

.create-form-container {
    width: 90%;
    background-color: rgba(255, 255, 255, 1);
    border-radius: 5px;
    margin: 10px auto;
}

.create-form-container h2 {
    text-align: center;
    font-size: 2rem;
}

.create-form-container {
    color: #333;
}

.create-form label {
    display: block;
    margin-bottom: 5px;
}

.create-form input[type="text"],
.create-form input[type="number"],
.create-form input[type="date"],
.create-form input[type="email"] {
    width: calc(100% - 12px);
    padding: 10px;
    margin-bottom: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
}

.create-form button[type="submit"],
.create-form button[type="button"] {
    width: auto;
    padding: 10px 20px;
    background-color: green;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    margin-right: 10px;
}

.create-form button[type="button"] {
    background-color: #dc3545;
}

.create-form a {
    width: 10%;
    padding: 10px;
    background-color: #0056b3;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    text-align: center;
    display: inline-block;
    text-decoration: none;
}
/* user.component.css */

.container {
    width: 50%;
    margin: 2rem auto;
    padding: 1.5vmax;
    padding-right: 2.5vmax;
    border: 1px solid #ccc;
    border-radius: 5px;
}

h2 {
    text-align: center;
    margin-bottom: 20px;
    font-size: 2rem;
}

.form-group {
    margin-bottom: 20px;
}

label {
    display: block;
    margin-bottom: 5px;
}

input[type="text"],
input[type="email"],
input[type="password"] {
    width: 97%;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
}

button[type="submit"] {
    width: 20%;
    padding: 1.1vmax;
    background-color: #0056b3;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-weight: bold;
    font-size: 1rem;
    align-self: center;
    margin-top: 1vmax;
}

.container {
    width: 50%;
    margin: 2rem auto;
    padding: 1.5vmax;
    padding-right: 3.5vmax;
    border: 1px solid #ccc;
    border-radius: 5px;
}

h2 {
    text-align: center;
    margin-bottom: 20px;
    font-size: 2rem;
}

.form-group {
    margin-bottom: 20px;
}

label {
    display: block;
    margin-bottom: 5px;
}

input[type="email"],
input[type="password"] {
    width: 99%;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
}

button[type="submit"] {
    width: 20%;
    padding: 1.1vmax;
    background-color: #0056b3;
    color: #fff;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-weight: bold;
    font-size: 1rem;
    align-self: center;
    margin-top: 1vmax;
}

.error-message {
    color: #FF0000;
    background-color: #FFEFEF;
    padding: 10px;
    border: 1px solid #FF0000;
    border-radius: 5px;
    margin-bottom: 10px;
    margin-top: 10px;
}

.success-message {
    color: green;
    background-color: rgb(186, 218, 186);
    padding: 10px;
    border: 1px solid green;
    border-radius: 5px;
    margin-bottom: 10px;
    margin-top: 10px;
}
// Address.component.ts

import { Component, OnInit } from "@angular/core";
import { AddressService } from "../address.service";
import { AuthService } from "../auth.service";
import { Router } from "@angular/router";
import { SharedService } from "../shared.service";
import { FormsModule } from "@angular/forms";
import { CommonModule } from "@angular/common";

@Component({
    selector: "app-address",
    standalone: true,
    imports: [FormsModule, CommonModule],
    templateUrl: "./address.component.html",
    styleUrl: "./address.component.css",
})
export class AddressComponent implements OnInit {
    isLoggedIn: boolean = false;
    addressList: any[] = [];
    displayedAddressList: any[] = [];
    addressById: any = {};
    addressUpdated: any = {};
    showUpdateForm: boolean = false;
    errorMessage: string = "";
    constructor(
        private addressService: AddressService,
        private userService: AuthService,
        private router: Router,
        private sharedService: SharedService
    ) { }
    ngOnInit(): void {
        if (typeof localStorage !== "undefined" && localStorage.getItem("token")) {
            this.getAllAddresses();
        }
    }

    ifLoggedIn(): boolean {
        this.userService.isAuthenticated().subscribe((isAuthenticated: boolean) => {
            this.isLoggedIn = isAuthenticated;
        });
        return this.isLoggedIn;
    }

    getUserId(): string | null {
        if (typeof localStorage !== "undefined") {
            const token = localStorage.getItem("token");
            if (token) {
                const tokenPayload = JSON.parse(atob(token.split(".")[1]));
                console.log(tokenPayload);
                return tokenPayload.user.id;
            }
        }
        return null;
    }

    getAllAddresses(): void {
        if (typeof localStorage !== "undefined") {
            const token = localStorage.getItem("token");
            if (token) {
                this.addressService
                    .getAllAddress(token)
                    .subscribe((addressList: any) => {
                        this.addressList = addressList;
                        this.displayedAddressList = [...this.addressList];
                    });
            }
        }
    }

    getAddressById(id: string): void {
        if (typeof localStorage !== "undefined") {
            const token = localStorage.getItem("token");
            if (token) {
                this.showUpdateForm = false;
                this.addressService
                    .getAddressById(id, token)
                    .subscribe((addressById: any) => {
                        this.addressById = addressById;
                        this.addressById.dob = this.addressById.dob.toString().slice(0, 10);
                    });
            }
        }
    }

    closeView(): void {
        this.addressById = {};
    }

    showAddFormFunction(): void {
        this.router.navigate(["/createAddress"]);
    }

    populateUpdateForm(address: any) {
        this.addressUpdated = { ...address };
        this.addressUpdated.dob = this.addressUpdated.dob.toString().slice(0, 10);
        this.showUpdateForm = true;
    }

    updateAddress(id: string): any {
        if (typeof localStorage !== "undefined") {
            const token = localStorage.getItem("token");
            if (token) {
                this.addressService.updateAddress(this.addressUpdated, token).subscribe(
                    (addressUpdated: any) => {
                        const index = this.displayedAddressList.findIndex(
                            (p) => p._id === id
                        );
                        if (index !== -1) {
                            this.addressList[index] = addressUpdated;
                            this.displayedAddressList[index] = addressUpdated;
                            this.getAllAddresses();
                            this.showUpdateForm = false;
                            this.router.navigate(["/getAllAddress"]);
                        }
                        this.cancelUpdate();
                    },
                    (error) => {
                        this.errorMessage = "Error Updating Activity";
                    }
                );
            }
        }
        return this.addressUpdated;
    }

    cancelUpdate(): void {
        this.showUpdateForm = false;
        this.addressUpdated = {};
        this.addressById = {};
    }

    confirmDelete(addressId: string): void {
        const confirmDelete = window.confirm(
            "Are you sure you want to delete this address?"
        );
        if (confirmDelete) {
            this.deleteAddress(addressId);
        }
    }

    deleteAddress(id: string): void {
        if (typeof localStorage !== "undefined") {
            const token = localStorage.getItem("token");
            if (token) {
                this.addressService.deleteAddress(id, token).subscribe(
                    () => {
                        this.addressList = this.addressList.filter(
                            (address: any) => address._id !== id
                        );
                        this.displayedAddressList = [...this.addressList];
                    },
                    (error) => {
                        this.errorMessage = "Error Deleting Address";
                    }
                );
            }
        }
    }
}
// Address-create.compoennt.ts

import { Component } from "@angular/core";
import { AddressService } from "../address.service";
import { AuthService } from "../auth.service";
import { Router } from "@angular/router";
import { SharedService } from "../shared.service";
import { FormsModule } from "@angular/forms";
import { CommonModule } from "@angular/common";

@Component({
    selector: "app-address-create",
    standalone: true,
    imports: [FormsModule, CommonModule],
    templateUrl: "./address-create.component.html",
    styleUrl: "./address-create.component.css",
})
export class AddressCreateComponent {
    isLoggedIn: boolean = false;
    addressCreated: any = {};
    showAddForm: boolean = false;
    errorMessage: string = "";
    constructor(
        private addressService: AddressService,
        private userService: AuthService,
        private router: Router,
        private sharedService: SharedService
    ) { }
    ngOnInit(): void { }

    createAddress(): void {
        if (typeof localStorage !== "undefined") {
            const token = localStorage.getItem("token");
            if (token) {
                this.addressService
                    .createAddress(this.addressCreated, token)
                    .subscribe((addressCreated) => {
                        this.addressCreated = addressCreated;
                        this.resetForm();
                        this.router.navigate(["/getAllAddress"]);
                    });
            }
        }
    }

    resetForm(): void {
        this.addressCreated = {};
    }
}
// User.component.ts

import { Component, OnInit } from "@angular/core";
import { AuthService } from "../auth.service";
import { Router } from "@angular/router";
import { SharedService } from "../shared.service";
import { FormsModule } from "@angular/forms";
import { CommonModule } from "@angular/common";

@Component({
    selector: "app-user",
    standalone: true,
    imports: [FormsModule, CommonModule],
    templateUrl: "./user.component.html",
    styleUrl: "./user.component.css",
})
export class UserComponent implements OnInit {
    username!: string;
    email!: string;
    password!: string;
    credentials: any = {};
    successMessage: string = "";
    errorMessage: string = "";
    loginActive: boolean = true;
    registerActive: boolean = false;
    constructor(
        private userService: AuthService,
        private router: Router,
        private sharedService: SharedService
    ) { }

    ngOnInit(): void {
        this.sharedService.loginEvent.subscribe(() => {
            this.loginActive = true;
            this.registerActive = false;
            this.username = "";
            this.email = "";
            this.password = "";
            this.successMessage = "";
            this.errorMessage = "";
        });
        this.sharedService.registerEvent.subscribe(() => {
            this.registerActive = true;
            this.loginActive = false;
            this.username = "";
            this.email = "";
            this.password = "";
            this.successMessage = "";
            this.errorMessage = "";
        });
    }

    login(): void {
        const credentials = {
            email: this.email,
            password: this.password,
        };
        this.userService.login(credentials).subscribe(
            (response: any) => {
                const token = response.token;
                localStorage.setItem("token", token);
                this.userService.setAuthenticationStatus(true);
                this.userService.emitLoggedInEvent();
                this.loginActive = false;
                this.registerActive = false;
                this.router.navigate(["/getAllAddress"]);
                this.successMessage = "User logged in successfully.";
                this.errorMessage = "";
            },
            (error: any) => {
                console.error("Error logging in:", error);
                this.errorMessage =
                    "Login unsuccessfull ! Please reload or try in incognito tab";
                this.successMessage = "";
            }
        );
    }

    register(): void {
        const userData = {
            username: this.username,
            email: this.email,
            password: this.password,
        };

        this.userService.register(userData).subscribe(
            (response: any) => {
                this.successMessage = response.message;
                this.errorMessage = "";
                this.loginActive = true;
                this.registerActive = false;
            },
            (error: any) => {
                this.errorMessage = "User not registered successfully";
                this.successMessage = "";
            }
        );
    }
}
// Address.service.ts

import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";

@Injectable({
    providedIn: "root",
})
export class AddressService {
    private baseUrl = "http://localhost:5000/api/address";
    constructor(private httpClient: HttpClient) { }

    getAllAddress(token: string): Observable<any> {
        const headers = new HttpHeaders({
            Authorization: `Bearer ${token}`,
        });
        return this.httpClient.get<any>(`${this.baseUrl}/getAllAddress`, {
            headers,
        });
    }

    getAddressById(id: string, token: string): Observable<any> {
        const headers = new HttpHeaders({
            Authorization: `Bearer ${token}`,
        });
        return this.httpClient.get<any>(`${this.baseUrl}/getAddressById/${id}`, {
            headers,
        });
    }

    createAddress(address: any, token: string): Observable<any> {
        const headers = new HttpHeaders({
            Authorization: `Bearer ${token}`,
        });
        return this.httpClient.post<any>(`${this.baseUrl}/createAddress`, address, {
            headers,
        });
    }

    updateAddress(address: any, token: string): Observable<any> {
        const headers = new HttpHeaders({
            Authorization: `Bearer ${token}`,
        });
        return this.httpClient.put<any>(
            `${this.baseUrl}/updateAddress/${address._id}`,
            address,
            { headers }
        );
    }

    deleteAddress(id: string, token: string): Observable<void> {
        const headers = new HttpHeaders({
            Authorization: `Bearer ${token}`,
        });
        return this.httpClient.delete<void>(`${this.baseUrl}/deleteAddress/${id}`, {
            headers,
        });
    }
}
// Auth.service.ts

import { HttpClient } from "@angular/common/http";
import { EventEmitter, Injectable } from "@angular/core";
import { BehaviorSubject, Observable } from "rxjs";

@Injectable({
    providedIn: "root",
})
export class AuthService {
    private baseUrl = "http://localhost:5000/api/auth";
    constructor(private httpClient: HttpClient) { }

    register(userData: any): Observable<any> {
        return this.httpClient.post(`${this.baseUrl}/register`, userData);
    }

    login(credentials: any): Observable<any> {
        return this.httpClient.post(`${this.baseUrl}/login`, credentials);
    }

    private isAuthenticatedSubject = new BehaviorSubject<boolean>(false);

    isAuthenticated(): Observable<boolean> {
        return this.isAuthenticatedSubject.asObservable();
    }

    setAuthenticationStatus(isAuthenticated: boolean): void {
        this.isAuthenticatedSubject.next(isAuthenticated);
    }

    loggedInEvent: EventEmitter<any> = new EventEmitter();
    emitLoggedInEvent() {
        this.loggedInEvent.emit();
    }
}
// Shared.service.ts

import { EventEmitter, Injectable } from '@angular/core';

@Injectable({
    providedIn: 'root'
})
export class SharedService {
    loginEvent: EventEmitter<void> = new EventEmitter<void>();
    registerEvent: EventEmitter<void> = new EventEmitter<void>();
    constructor() { }

    triggerLoginEvent(): void {
        this.loginEvent.emit();
    }

    triggerRegisterEvent(): void {
        this.registerEvent.emit();
    }
}
// app.component.ts

import { Component } from "@angular/core";
import { Router, RouterOutlet } from "@angular/router";
import { SharedService } from "./shared.service";
import { AuthService } from "./auth.service";
import { FormsModule } from "@angular/forms";
import { CommonModule } from "@angular/common";

@Component({
    selector: "app-root",
    standalone: true,
    imports: [RouterOutlet, FormsModule, CommonModule],
    templateUrl: "./app.component.html",
    styleUrl: "./app.component.css",
})
export class AppComponent {
    title = "GeeksForGeeks Address Book";
    isLoggedIn: boolean = false;
    constructor(
        private router: Router,
        private userService: AuthService,
        private sharedService: SharedService
    ) { }
    ngOnInit(): void {
        this.userService.loggedInEvent.subscribe((data: any) => {
            this.isLoggedIn = true;
        });
        if (typeof localStorage !== "undefined" && localStorage.getItem("token")) {
            this.isLoggedIn = true;
        }
    }

    login(): void {
        this.sharedService.triggerLoginEvent();
        this.router.navigate(["/"]);
    }

    register(): void {
        this.sharedService.triggerRegisterEvent();
        this.router.navigate(["/"]);
    }

    logout(): void {
        this.userService.setAuthenticationStatus(false);
        this.isLoggedIn = false;
        localStorage.removeItem("token");
        this.router.navigate(["/"]);
    }
}
// app.routes.ts

import { Routes } from "@angular/router";
import { AddressComponent } from "./address/address.component";
import { AddressCreateComponent } from "./address-create/address-create.component";
import { UserComponent } from "./user/user.component";

export const routes: Routes = [
    { path: "", component: UserComponent },
    { path: "getAllAddress", component: AddressComponent },
    { path: "getAddressById/:id", component: AddressComponent },
    { path: "createAddress", component: AddressCreateComponent },
    { path: "updateAddress/:id", component: AddressComponent },
    { path: "deleteAddress/:id", component: AddressComponent },
    { path: "**", redirectTo: "/" },
];
// app.module.ts

import { InjectionToken, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { JwtHelperService, JWT_OPTIONS } from '@auth0/angular-jwt';
import { RouterModule } from '@angular/router';
import { routes } from './app.routes';
import { AddressComponent } from './address/address.component';
import { AddressCreateComponent } from './address-create/address-create.component';
import { UserComponent } from './user/user.component';
@NgModule({
    declarations: [
        AppComponent,
        UserComponent,
        AddressComponent,
        AddressCreateComponent,
    ],
    imports: [
        BrowserModule,
        FormsModule,
        RouterModule.forRoot(routes),
    ],
    exports: [RouterModule],
    providers: [{ provide: JWT_OPTIONS, useValue: JWT_OPTIONS }, JwtHelperService],
    bootstrap: [AppComponent]
})
export class AppModule { }

To start the angular application run the following command.

ng serve

Output:

Address book using Mean

Address Book using MEAN

Article Tags :