33 Capstone: Adding a chat feature to Confetti Cuisine
As the Confetti Cuisine application nears release, the author adds a simple, real-time chat feature to boost user engagement without overcomplicating the codebase. The chat is restricted to authenticated users and leverages socket.io to maintain a live connection between clients and the server, enabling event-driven messaging. A small UX enhancement ties chat activity to a navigation icon that animates when new messages arrive, offering app-wide awareness of ongoing conversations.
The implementation begins by installing socket.io, integrating it with the existing Express server, and separating chat logic into a dedicated controller. Server-side handlers respond to connection, disconnect, and custom message events, broadcasting messages to all connected clients. On the client, a new chat route and EJS view include a form with hidden fields for the user’s name and ID, while client-side JavaScript initializes a socket, emits messages on form submit, and renders incoming messages in the chat box. The display logic tags messages with the sender’s name and visually distinguishes the current user’s messages.
To persist chat history, a Mongoose Message model stores content, user name, and user ID, with timestamps for auditing. The server saves each incoming message and, on new connections, loads and emits the ten most recent messages so newcomers see recent context. After verifying real-time behavior across multiple browsers, the author enhances visibility by animating a chat icon whenever messages are received, and notes potential future expansions such as per-class chat rooms or tagging notifications.
Summary
In this capstone exercise, I added a real-time chat feature to my Confetti Cuisine application. I used socket.io to simplify connections between the server and multiple clients. I used some built-in and custom events to transfer data between open sockets. At the end, I added a feature to notify users who aren’t in the chat room that others are actively communicating. With this feature added, I’m ready to deploy the application.
FAQ
What does the new chat feature do and who can use it?
The chat enables real-time messaging between authenticated users only. Each message is associated with the sender (name and user ID) and broadcast to all connected clients. A chat icon in the navigation bar links to the chat page and can animate to indicate new activity.How do I install socket.io and make it available on both server and client?
- Install: runnpm i socket.io -S.- Server: save your Express server instance (e.g.,
const server = app.listen(...)) and initialize Socket.IO with const io = require('socket.io')(server).- Client: include
<script src="/socket.io/socket.io.js"></script> in your layout before your app’s JS, then call const socket = io() in client code.How do I wire Socket.IO to my existing Express server?
Assignapp.listen(...) to a server variable and pass it to require('socket.io') like const io = require('socket.io')(server). This ensures Socket.IO shares the same HTTP server as your Express app.Which Socket.IO events are handled on the server?
-io.on('connection'): runs when a client connects.-
client.on('disconnect'): runs when a client disconnects.-
client.on('message'): receives a message payload, builds a message object (content, userName, userId), and broadcasts it with io.emit('message', ...) to all clients.How do I add the /chat route and view?
Add a route likerouter.get('/chat', homeController.chat), and in the controller render res.render('chat'). In chat.ejs, show the chat UI only if currentUser is present and include a form with an input for the message plus hidden inputs for userId and userName.How does the client send and receive messages?
On the client, initializeconst socket = io(). On form submit, read the message text and the hidden user fields, then socket.emit('message', { content, userName, userId }). Also listen with socket.on('message', handler) to display incoming messages immediately.How are messages rendered, and how can I highlight the current user’s messages?
Use adisplayMessage(message) function to prepend messages to the chat area. Include message.userName alongside message.content. Compare the hidden userId in the page to message.user and, if they match, add a CSS class (e.g., current-user) so the sender’s own messages are styled differently.How are chat messages persisted in the database?
Create a Mongoose model (e.g.,Message) with required fields: content (String), userName (String), and user (ObjectId referencing User), and enable timestamps. In the server’s client.on('message') handler, instantiate and save a Message. On successful save, emit the message to all clients.How do new users see recent chat history when they connect?
On connection, query the DB for the 10 most recent messages (e.g.,find({}).sort({ createdAt: -1 }).limit(10)), reverse them for chronological display, and emit them to the connecting socket via a custom event like 'load all messages'. On the client, handle this event and display each message.How do I add and animate the chat icon in the navbar?
Add a link in your layout like<a href="/chat" class="chat-icon">@</a>. In the client’s socket.on('message') handler, after displaying the message, briefly fade the element with class .chat-icon out and back in twice to indicate new activity.
Get Programming with Node.js ebook for free