├── .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 |
25 |
26 |
27 |
28 |

Add a Note

29 | 37 | 38 | 45 | 46 |
47 |
48 |
49 |
50 |
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 | --------------------------------------------------------------------------------