├── .babelrc
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
└── src
├── app.js
├── config.js
├── db.js
├── index.js
├── models
└── Note.js
├── public
├── index.html
├── main.css
├── main.js
├── sockets.js
└── ui.js
└── sockets.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"],
3 | "plugins": ["@babel/plugin-transform-runtime"],
4 | "ignore": [
5 | "src/public/**/*.js"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | .env
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Socket.io CRUD
2 |
3 | This is a simple CRUD web application in real-time using Socket.io and Nodejs
4 |
5 | ### Requeriments
6 |
7 | * Mongodb
8 |
9 | ### Installation
10 |
11 | ```
12 | git clone https://github.com/FaztWeb/websockets-nodejs-crud
13 | ```
14 |
15 | ```
16 | cd websockets-nodejs-crud
17 | ```
18 |
19 | ```
20 | npm install
21 | ```
22 |
23 | To execute in development mode
24 |
25 | ```
26 | npm run dev
27 | ```
28 |
29 | to build the project for production
30 | ```
31 | npm run build
32 | npm start
33 | ```
34 |
35 | #### Resources
36 | * https://socket.io/docs/v3/testing/
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nodejs-mongodb-socketio-crud",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "dev": "nodemon src/index.js --exec babel-node --ignore src/public",
8 | "build": "babel src -d dist --copy-files",
9 | "start": "node dist"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "@babel/runtime": "^7.17.0",
16 | "dotenv": "^16.0.0",
17 | "express": "^4.17.2",
18 | "mongoose": "^6.2.0",
19 | "socket.io": "^4.4.1"
20 | },
21 | "devDependencies": {
22 | "@babel/cli": "^7.17.0",
23 | "@babel/core": "^7.17.0",
24 | "@babel/node": "^7.16.8",
25 | "@babel/plugin-transform-runtime": "^7.17.0",
26 | "@babel/preset-env": "^7.16.11",
27 | "nodemon": "^2.0.15"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/app.js:
--------------------------------------------------------------------------------
1 | import express from "express";
2 | const app = express();
3 |
4 | app.use(express.static(__dirname + "/public"));
5 |
6 | export default app;
7 |
--------------------------------------------------------------------------------
/src/config.js:
--------------------------------------------------------------------------------
1 | import { config } from "dotenv";
2 | config();
3 |
4 | export const PORT = process.env.PORT || 3000;
5 | export const MONGODB_URI =
6 | process.env.MONGODB_URI || "mongodb://localhost/socketsdb";
7 |
--------------------------------------------------------------------------------
/src/db.js:
--------------------------------------------------------------------------------
1 | import { connect } from "mongoose";
2 | import { MONGODB_URI } from "./config";
3 |
4 | export const connectDB = async () => {
5 | try {
6 | await connect(MONGODB_URI);
7 | console.log("Connected to db");
8 | } catch (error) {
9 | console.error(error);
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { Server as WebSocketServer } from "socket.io";
2 | import http from "http";
3 | import Sockets from "./sockets";
4 | import app from "./app";
5 | import { connectDB } from "./db";
6 | import { PORT } from "./config";
7 |
8 | connectDB();
9 | const server = http.createServer(app);
10 | const httpServer = server.listen(PORT);
11 | console.log("Server on http://localhost:", PORT);
12 |
13 | const io = new WebSocketServer(httpServer);
14 |
15 | Sockets(io);
16 |
--------------------------------------------------------------------------------
/src/models/Note.js:
--------------------------------------------------------------------------------
1 | import { Schema, model } from "mongoose";
2 |
3 | const schema = new Schema(
4 | {
5 | title: {
6 | type: String,
7 | required: true,
8 | },
9 | description: {
10 | type: String,
11 | },
12 | },
13 | {
14 | timestamps: true,
15 | }
16 | );
17 |
18 | export default model("Note", schema);
19 |
--------------------------------------------------------------------------------
/src/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Chat 2021
8 |
9 |
15 |
16 |
17 |
21 |
22 |
23 |
24 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/src/public/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | height: 100vh;
3 | background: beige;
4 | }
5 |
--------------------------------------------------------------------------------
/src/public/main.js:
--------------------------------------------------------------------------------
1 | import { appendNote, renderNotes, fillForm, onHandleSubmit } from "./ui.js";
2 | import { loadNotes, onNewNote, onSelected } from "./sockets.js";
3 |
4 | // Load initial Notes
5 | window.addEventListener("DOMContentLoaded", () => {
6 | loadNotes(renderNotes);
7 | onNewNote(appendNote);
8 | onSelected(fillForm);
9 | });
10 |
11 | // Save a new Note
12 | const noteForm = document.querySelector("#noteForm");
13 | noteForm.addEventListener("submit", onHandleSubmit);
14 |
--------------------------------------------------------------------------------
/src/public/sockets.js:
--------------------------------------------------------------------------------
1 | const socket = io.connect();
2 |
3 | /**
4 | * create a new note
5 | * @param {string} title a title for a new note
6 | * @param {string} description a description for a new note
7 | */
8 | export const saveNote = (title, description) => {
9 | socket.emit("client:newnote", {
10 | title,
11 | description,
12 | });
13 | };
14 |
15 | /**
16 | * delete a note based on an Id
17 | * @param {string} id a note ID
18 | */
19 | export const deleteNote = (id) => {
20 | socket.emit("client:deletenote", id);
21 | };
22 |
23 | /**
24 | *
25 | * @param {string} id note ID
26 | * @param {string} title note title
27 | * @param {string} description note description
28 | */
29 | export const updateNote = (_id, title, description) => {
30 | socket.emit("client:updatenote", {
31 | _id,
32 | title,
33 | description,
34 | });
35 | };
36 |
37 | /**
38 | * Load an Array of Notes
39 | * @param {function} callback A function to render Notes
40 | */
41 | export const loadNotes = (callback) => {
42 | socket.on("server:loadnotes", callback);
43 | };
44 |
45 | export const onNewNote = (callback) => {
46 | socket.on("server:newnote", callback);
47 | };
48 |
49 | export const onSelected = (callback) => {
50 | socket.on("server:selectednote", callback);
51 | };
52 |
53 | export const getNoteById = (noteId) => {
54 | socket.emit("client:getnote", noteId);
55 | };
56 |
--------------------------------------------------------------------------------
/src/public/ui.js:
--------------------------------------------------------------------------------
1 | import { deleteNote, getNoteById, saveNote, updateNote } from "./sockets.js";
2 |
3 | const notesList = document.querySelector("#notes");
4 | const title = document.querySelector("#title");
5 | const description = document.querySelector("#description");
6 |
7 | let savedId = "";
8 |
9 | const noteUI = (note) => {
10 | const div = document.createElement("div");
11 | div.innerHTML = `
12 |
13 |
14 |
${note.title}
15 |
16 |
17 |
18 |
19 |
20 |
${note.description}
21 |
22 | `;
23 | const btnDelete = div.querySelector(".delete");
24 | const btnUpdate = div.querySelector(".update");
25 |
26 | btnDelete.addEventListener("click", () => deleteNote(btnDelete.dataset.id));
27 | btnUpdate.addEventListener("click", () => getNoteById(btnDelete.dataset.id));
28 |
29 | return div;
30 | };
31 |
32 | export const renderNotes = (notes) => {
33 | savedId = "";
34 | notesList.innerHTML = "";
35 | notes.forEach((note) => notesList.append(noteUI(note)));
36 | };
37 |
38 | export const appendNote = (note) => {
39 | notesList.append(noteUI(note));
40 | };
41 |
42 | export const fillForm = (note) => {
43 | title.value = note.title;
44 | description.value = note.description;
45 |
46 | savedId = note._id;
47 | };
48 |
49 | export const onHandleSubmit = (e) => {
50 | e.preventDefault();
51 | if (savedId) {
52 | updateNote(savedId, title.value, description.value);
53 | } else {
54 | saveNote(title.value, description.value);
55 | }
56 |
57 | title.value = "";
58 | description.value = "";
59 | };
60 |
--------------------------------------------------------------------------------
/src/sockets.js:
--------------------------------------------------------------------------------
1 | import Note from "./models/Note";
2 |
3 | export default (io) => {
4 | io.on("connection", (socket) => {
5 | // console.log(socket.handshake.url);
6 | console.log("nuevo socket connectado:", socket.id);
7 |
8 | // Send all messages to the client
9 | const emitNotes = async () => {
10 | const notes = await Note.find();
11 | socket.emit("server:loadnotes", notes);
12 | };
13 | emitNotes();
14 |
15 | socket.on("client:newnote", async (data) => {
16 | const newNote = new Note(data);
17 | const savedNote = await newNote.save();
18 | io.emit("server:newnote", savedNote);
19 | });
20 |
21 | socket.on("client:deletenote", async (noteId) => {
22 | await Note.findByIdAndDelete(noteId);
23 | emitNotes();
24 | });
25 |
26 | socket.on("client:getnote", async (noteId) => {
27 | const note = await Note.findById(noteId);
28 | socket.emit("server:selectednote", note);
29 | });
30 |
31 | socket.on("client:updatenote", async (updatedNote) => {
32 | await Note.findByIdAndUpdate(updatedNote._id, {
33 | title: updatedNote.title,
34 | description: updatedNote.description,
35 | });
36 | emitNotes();
37 | });
38 |
39 | socket.on("disconnect", () => {
40 | console.log(socket.id, "disconnected");
41 | });
42 | });
43 | };
44 |
--------------------------------------------------------------------------------