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-taking.
.png) Final Output Prerequisites:Functionalities of Notes Maker AppThe project employs a backend built with Node.js and Express.js, utilizing MongoDB as the database for note storage. On the front end, Angular.js is employed to create an interactive user interface. The functionalities include:
- Adding new notes with titles and content.
- Displaying a list of existing notes.
- Update/Delete Notes.
Steps to Create the ProjectStep 1: Create a new directory for your project and navigate to it using the terminal.
mkdir NOTEAPP cd NOTEAPP Step 2: Create a server directory for your backend and navigate into it.
mkdir server cd server Step 3: Initialize a new Node.js project for the backend.
npm init -y Step 4: Install the necessary backend dependencies.
npm install express mongoose cors Project Structure (Backend):.png) Backed Structure Dependencies (Backend):"dependencies": { "cors": "^2.8.5", "express": "^4.19.2", "mongoose": "^8.4.0" } Step 5: Create a server.js file inside the server directory and add the following code:
JavaScript
// server.js
const express = require("express");
const mongoose = require("mongoose");
const noteRoutes = require("./routes/noteRoutes");
const cors = require("cors");
const app = express();
const port = 5000;
// Connect to MongoDB
mongoose
.connect("mongodb://localhost:27017/note-app")
.then(() => {
console.log("Connected successfully to MongoDB");
})
.catch((err) => {
console.error("Error occurred while connecting to MongoDB:", err);
});
// Middleware
app.use(express.json());
app.use(cors());
app.use(express.urlencoded({ extended: true }));
app.use("/notes", noteRoutes);
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
JavaScript
// model/note.js
const mongoose = require("mongoose");
const noteSchema = new mongoose.Schema({
title: { type: String, },
description: { type: String, },
});
module.exports = mongoose.model("Note", noteSchema);
JavaScript
// routes/noteRoutes.js
const express = require("express");
const router = express.Router();
const Note = require("../model/note");
const note = require("../model/note");
// Get all notes
router.get("/", async (req, res) => {
try {
const notes = await Note.find();
res.json(notes);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
// Create a note
router.post("/", async (req, res) => {
console.log(req.body);
const note = new Note({
title: req.body.title,
description: req.body.description,
});
try {
const newNote = await note.save();
res.status(201).json(newNote);
} catch (err) {
res.status(400).json({ message: err.message });
}
});
// Update a note
router.put("/:id", async (req, res) => {
console.log(req.params.id);
try {
const note = await Note.findById(req.params.id);
if (note == null) {
return res.status(404).json({ message: "Note not found" });
}
if (req.body.title != null) {
note.title = req.body.title;
}
if (req.body.description != null) {
note.description = req.body.description;
}
const updatedNote = await note.save();
res.json(updatedNote);
} catch (err) {
res.status(400).json({ message: err.message });
}
});
// Delete a note
router.delete("/:id", async (req, res) => {
try {
const deletedNote = await Note.findByIdAndDelete(req.params.id);
const notes = await Note.find();
res.json(notes);
} catch (err) {
res.status(500).json({ message: err.message });
}
});
module.exports = router;
To run the backend server run the following command.
node server.js Step 6: Navigate to the root directory. Run the following command to initialize a new Angular app:
npm install -g @angular/cli cd client ng new note-maker-app Folder Structure(Frontend):.png) Front End Structure Dependencies(Frontend):"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" } Example: Add the given code in the respective files.
HTML
<!-- /src/app/app.component.html -->
<div class="note-form">
<h2>Note Maker App</h2>
<form (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="title">Title:</label>
<input
type="text"
id="title"
placeholder="Enter Note Title..."
[(ngModel)]="title"
name="title"
required
/>
</div>
<div class="form-group">
<label for="location">Description:</label>
<input
type="text"
id="location"
placeholder="Enter Description..."
[(ngModel)]="description"
name="description"
required
/>
</div>
<button type="submit">Submit</button>
</form>
<div class="existing-notes">
<h2>Existing Notes</h2>
<ul>
<li *ngFor="let note of notes">
<div class="notes-details">
<strong>Title:</strong> {{ note.title }},
<strong>Description</strong> {{ note.description }},
</div>
<div class="notes-actions">
<button class="editbtn" (click)="editNote(note)">Edit</button>
<button class="deletebtn" (click)="deleteNote(note._id)">Delete</button>
</div>
</li>
</ul>
</div>
</div>
CSS
/* app.component.css */
body {
font-family: 'Roboto', sans-serif;
background: linear-gradient(to right, #ff6e7f, #bfe9ff);
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-attachment: fixed;
}
/* Container */
.note-form {
background-color: #ffffff;
margin: 0 auto;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
width: 500px;
text-align: left;
border-top: 5px solid #d9534f;
position: relative;
overflow: hidden;
background-image: url('https://example.com/disaster-background.jpg');
background-size: cover;
background-position: center;
background-blend-mode: overlay;
}
.emergency-form::before {
content: '';
background: rgba(255, 255, 255, 0.8);
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 0;
}
.emergency-form > * {
position: relative;
z-index: 1;
}
/* Headings */
h2 {
color: green;
margin-top: 0;
border-bottom: 2px solid green;
padding-bottom: 10px;
font-size: 24px;
}
/* Paragraph */
p {
color: #555;
margin: 10px 0;
font-size: 16px;
}
/* Form Styles */
form {
margin-top: 20px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
color: #333;
font-weight: bold;
margin-bottom: 5px;
}
.form-group input {
width: 100%;
padding: 12px;
border: 1px solid #ccc;
border-radius: 5px;
box-sizing: border-box;
font-size: 16px;
}
/* Button Styles */
button {
width: 100%;
padding: 15px;
background-color:green;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 18px;
font-weight: bold;
margin-top: 20px;
transition: background-color 0.3s, transform 0.3s;
}
button:hover {
transform: scale(1.05);
}
.editbtn{
width: 50%;
margin: 1px;
background-color:green;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 18px;
font-weight: bold;
margin-top: 20px;
transition: background-color 0.3s, transform 0.3s;
}
.deletebtn{
width: 50%;
margin: 1px;
background-color:red;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 18px;
font-weight: bold;
margin-top: 20px;
transition: background-color 0.3s, transform 0.3s;
}
/* Existing Emergencies Section */
.existing-notes {
margin-top: 40px;
}
.existing-notes h2 {
color: #d9534f;
}
.existing-notes ul {
list-style: none;
padding: 0;
}
.existing-notes li {
background-color: #f9f9f9;
border: 1px solid #ddd;
padding: 15px;
margin-bottom: 15px;
border-radius: 5px;
position: relative;
display: flex;
justify-content: space-between; /* Aligns content and actions side by side */
align-items: center;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
transition: transform 0.3s, box-shadow 0.3s;
}
.existing-notes li:hover {
transform: translateY(-5px);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}
.existing-notes li::before {
content: '????';
position: absolute;
left: 10px;
top: 10px;
font-size: 24px;
color: #0e4b07;
}
.existing-notes li strong {
color: #333;
display: block;
}
/* Media Queries for Responsive Design */
@media (max-width: 600px) {
.emergency-form {
width: 100%;
padding: 20px;
}
.form-group input,
button {
padding: 10px;
}
button {
font-size: 16px;
}
}
JavaScript
// /src/app/app.component.ts
import { Component, OnInit } from '@angular/core';
import { HttpClient, HttpClientModule } from '@angular/common/http'; // Import HttpClientModule
import { FormsModule } from '@angular/forms'; // Import FormsModule for ngModel
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
imports: [
CommonModule,
FormsModule, // Add FormsModule here
HttpClientModule // Add HttpClientModule here
],
standalone: true
})
export class AppComponent implements OnInit {
// Form inputs
title = '';
description = '';
notes: any[] = [];
constructor(private http: HttpClient) { }
ngOnInit(): void {
this.fetchNotes();
}
fetchNotes(): void {
this.http.get<any[]>('http://localhost:5000/notes').subscribe(
(data) => {
this.notes = data;
},
(error) => {
console.error('Error fetching notes:', error);
}
);
}
// Handle form submission
onSubmit(): void {
if (this.title.trim() === '' || this.description.trim() === '') {
alert('Please fill in all fields!');
return;
}
const newNote = {
title: this.title,
description: this.description,
};
this.http.post('http://localhost:5000/notes', newNote).subscribe(
(data) => {
console.log('Data submitted:', data);
// Reset form inputs
this.title = '';
this.description = '';
this.fetchNotes();
},
(error) => {
console.error('Error submitting data:', error);
}
);
}
editNote(note: any): void {
console.log(note)
const newTitle = prompt('Enter new title:', note.title);
const newDescription = prompt('Enter new description:', note.description);
if (newTitle !== null && newDescription !== null) {
const updatedNotes = { ...note, title: newTitle, description: newDescription };
this.http.put(`http://localhost:5000/notes/${note._id}`, updatedNotes).subscribe(
(data) => {
console.log('Updated note:', data);
this.fetchNotes(); // Refresh the list
},
(error) => {
console.error('Error updating notes:', error);
}
);
}
}
deleteNote(id: number): void {
this.http.delete<any[]>('http://localhost:5000/notes/' + id).subscribe(
(updatedNotes) => {
this.notes = updatedNotes;
},
(error) => {
console.error('Error deleting notes:', error);
}
);
}
}
JavaScript
//main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));
To run the application, type the following command:
ng serve Output:
 Notes Maker app using MEAN stack
|