Organizing communications in NodeJS messaging application

My latest project involves creating a chat room using NodeJS and socket.io which allows multiple users to connect with unique usernames. Everything is running smoothly, except for one minor issue.

I want the messages sent by me to appear in a different color compared to messages sent by other users. I attempted to use even odd logic in CSS, but it didn't work as expected when I sent multiple messages simultaneously.

Below is the structure of my Index.html file:

    <div id="wrapper">
    <div id="usernameWrap">
        <p id="usernameError"></p>
        <form id="setUsername">
            <input class="message" id="username" placeholder="Enter your Username"/>
            <input class="button" type="submit" value="SUBMIT"/>
        </form>
    </div>

    <div id="chatWrapper">
        <ul id="chat"></ul>
        <form id="send-message">
            <input class="message" type="text" id="message" placeholder="Type a message" autocomplete="off" />
            <input class="button" type="submit" value="SEND"/>
        </form>
    </div>
</div>
    <script src="/socket.io/socket.io.js"></script>
    <script>
        jQuery(function($){
            var socket =io.connect();
            var $usernameForm = $('#setUsername');
            var $usernameError = $('#usernameError');
            var $username = $('#username');
            var $messageForm = $('#send-message');
            var $messageBox = $('#message');
            var $chat = $('#chat');

            /* setting username */

            $usernameForm.submit(function(e){
                e.preventDefault();
                socket.emit('new user',$username.val(),function(data){
                    if(data){
                        $('#usernameWrap').hide();
                        $('#chatWrapper').show();
                    } else{
                        $usernameError.html('Username is already Taken!');
                    }
                });
                $username.val('');
            });

            /* sending and receiving messages */

            $messageForm.submit(function(e){
                e.preventDefault();
                socket.emit('send message',$messageBox.val());
                $messageBox.val('');
            });

            socket.on('new message',function(data){
                $chat.append('<li><b>' + data.username + ': </b>' + data.message + "<br/></li>");
            });
        });
    </script>

Below is the content of my App.js file:

var express = require('express'),
    app = express(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server);
    usernames=[];

app.use('/css', express.static(__dirname + '/css'));

server.listen(8081);

app.get('/',function(req,res){
    res.sendFile(__dirname + '/index.html')
});

io.sockets.on('connection',function(socket){
    socket.on('new user',function(data,callback){
        if(usernames.indexOf(data) != -1){
            callback(false);
        } else{
            callback(true);
            socket.username = data;
            usernames.push(socket.username);
            io.sockets.emit('usernames',usernames);
        }
    });

    socket.on('send message',function(data){
        io.sockets.emit('new message',{message:data,username:socket.username});
    });

    socket.on('disconnect',function(data){
        if(!socket.username) return;
        usernames.splice(usernames.indexOf(socket.username),1);
    });
});

Thank you for taking the time to review my project.

Answer №1

Consider enhancing your CSS with color classes:

.blueText {
    color: #00F;
}
.greenText {
    color: #0F0;
}

Let the server determine the color class according to the user's name:

socket.on('send message',function(data){
    var userColorClass = "greenText";
    if( socket.username === "root" ) {
        userColorClass = "blueText";
    }
    io.sockets.emit('new message',{
        message:data,
        colorClass: userColorClass,
        username:socket.username
    });
});

Lastly, add the class name to your browser JavaScript code:

        socket.on('new message',function(data){
            $chat.append('<li class="' + data.colorClass + '"><b>' +
                data.username + ': </b>' + data.message + "<br/></li>");
        });

This approach allows you to assign colors based on user names or any other criteria you desire.

Answer №2

Ensure that when a message is added to the chat log, you verify whether data.username matches the current user's name. If they are the same, apply a class to the HTML element being generated. Utilize CSS to apply a unique style to this class.

Answer №3

Special thanks to Hughes and Lee for their insightful suggestions which helped me successfully resolve the issue.

I captured the user's inputted username, stored it in a variable, and cross-checked it with data.username.

Below are the updated index.html and app.js files:

Index.html

<!doctype html>
<html>
<head>
    <title>Socket.IO chat</title>
    <!-- styles -->
    <link rel="stylesheet" type="text/css" href="css/style.css">
    <!-- scripts -->
    <script src="https://code.jquery.com/jquery-latest.min.js"></script>

</head>
<body>
<div id="wrapper">
    <div id="usernameWrap">
        <p id="usernameError"></p>
        <form id="setUsername">
            <input class="message" id="username" placeholder="Enter your Username"/>
            <input class="button" type="submit" value="SUBMIT"/>
        </form>
    </div>

    <div id="chatWrapper">
        <ul id="chat"></ul>
        <form id="send-message">
            <input class="message" type="text" id="message" placeholder="Type a message" autocomplete="off" />
            <input class="button" type="submit" value="SEND"/>
        </form>
    </div>
</div>
    <script src="/socket.io/socket.io.js"></script>
    <Script>
        jQuery(function($){
            var socket =io.connect();
            var $usernameForm = $('#setUsername');
            var $usernameError = $('#usernameError');
            var $username = $('#username');
            var $messageForm = $('#send-message');
            var $messageBox = $('#message');
            var $chat = $('#chat');
            var $currentUser;

            /* setting username */

            $usernameForm.submit(function(e){
                e.preventDefault();
                socket.emit('new user',$username.val(),function(data){
                    if(data){
                        $('#usernameWrap').hide();
                        $('#chatWrapper').show();
                    } else{
                        $usernameError.html('Username is already Taken!');
                    }
                });
                $currentUser = $username.val();
                $username.val('');
            });

            /* sending and receiving messages */

            $messageForm.submit(function(e){
                e.preventDefault();
                socket.emit('send message',$messageBox.val());
                $messageBox.val('');
            });

            socket.on('new message',function(data){
                if(data.username === $currentUser){
                    data.colorClass = "blueText";
                } else{
                    data.colorClass = "greenText";
                }
                $chat.append('<li class="' + data.colorClass + '"><b>' + data.username + ': </b>' + data.message + "<br/></li>");
            });
        });
    </Script>
</body>
</html>

App.js:

var express = require('express'),
    app = express(),
    server = require('http').createServer(app),
    io = require('socket.io').listen(server);
    usernames=[];

app.use('/css', express.static(__dirname + '/css'));

server.listen(8081);

app.get('/',function(req,res){
    res.sendFile(__dirname + '/index.html')
});

io.sockets.on('connection',function(socket){
    socket.on('new user',function(data,callback){
        if(usernames.indexOf(data) != -1){
            callback(false);
        } else{
            callback(true);
            socket.username = data;
            usernames.push(socket.username);
            io.sockets.emit('usernames',usernames);
        }
    });

    socket.on('send message',function(data){
        io.sockets.emit('new message',{message:data,username:socket.username});
    });

    socket.on('disconnect',function(data){
        if(!socket.username) return;
        usernames.splice(usernames.indexOf(socket.username),1);
    });
});

Answer №4

This solution was a game-changer for me. I needed to adjust the alignment of sender and receiver messages, and with the help of suggestions from others, I was able to come up with a dynamic solution.

// Setting up socket.io on the client side
let socket = io();

// Storing the client's socket.id in a variable
let clientSocketId;

// Sending the clientSocketId when emitting the event from the browser to the server
$messageForm.submit(function(e){
    e.preventDefault();

    // Storing the unique socket id
    clientSocketId = socket.id;

    // Emitting the data as usual
    socket.emit('send message', {
        message: $messageBox.val(),
        username: $username.val(),
        clientId: clientSocketId
    });
    $messageBox.val('');
});


// On the server side, using version 2.0.4
io.on('connection', function(socket){
    console.log('a user is connected');

    socket.on('send message', function(data) {
    
        io.emit('new message', { 
            message: data.message,
            username: data.username,
            clientId: data.clientId
        })
    
    })
})

// Back on the client side
socket.on('new message', function(data){

    // Checking if the clientSocketId returned from the server matches the one sent by the client
    if(clientSocketId === data.clientId) {

        $chat.append('<li class='blueText'><b>' + data.username + ': </b>' + data.message + "<br/></li>");
    } else {
        $chat.append('<li class='greenClass'><b>' + data.username + ': </b>' + data.message + "<br/></li>");
    }
  
})
.blueText {
    color: #00F;
}
.greenText {
    color: #0F0;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Activate event using jQuery in webpack and manage it on the page

I'm currently in the process of revamping a large application using React. One challenge I've encountered is refreshing a datatable on the page after a successful form submission, as the datatable isn't controlled by React or webpack. I trie ...

Tips for customizing the time selector in material-ui-time-picker

Is there a way to enable keyboard input control for the material-ui-time-picker? Currently, it only allows editing when clicking on the clock interface. Here is a snippet of my code: import React, { Component } from "react"; import { TimePicker } from " ...

Getting a specific piece of information from a JSON file

I am encountering an issue with my JSON file collection. When I access it through http://localhost:5000/product/, I can see the contents without any problem. However, when I try to retrieve a specific product using a link like http://localhost:5000/product ...

Can I exclusively utilize named exports in a NextJS project?

Heads up: This is not a repeat of the issue raised on The default export is not a React Component in page: "/" NextJS I'm specifically seeking help with named exports! I am aware that I could switch to using default exports. In my NextJS ap ...

Guide on utilizing jQuery/AJAX data with PassportJS

When I submit a login request using the form fields action="/login", method="post", everything works smoothly. This is similar to the code examples found either here or here. However, when I attempt to send the same information using jquery/ajax, passport ...

What is the reason for needing to export the function when importing a module in an Angular appModule?

I came across the following code snippet @NgModule({ declarations: [ ... ], imports: [ RoutingModule, SharedModule, JwtModule.forRoot({ config: { headerName: 'Authorization', tokenGetter: () => lo ...

Validation of HTML forms through JavaScript

I'm working on form validation and struggling with implementing preg_match check from a variable. Currently, I can validate empty fields successfully, but that's not sufficient. Any suggestions on how to proceed? var pattern = /([a-zA-Z0-9]|[a-z ...

What is the optimal strategy for managing multilingual text in a React website?

As I develop a react website with multiple localizations, I am faced with the question of how to best store UI texts for different languages. Currently, I am contemplating two approaches: One option is to store text directly in the UI code, using an objec ...

lint-staged executes various commands based on the specific folder

Within my project folder, I have organized the structure with two subfolders: frontend and backend to contain their respective codebases. Here is how the root folder is set up: - backend - package.json - other backend code files - frontend - p ...

Obtain data with matching JSON values in a REACT application

Recently, I received a JSON file that looks something like this: [ { "symbol": "A", "name": "Agilent Technologies Inc", "exchange": "NYSE", }, { "symbol": "AAC ...

How can I change the background color of my notification box to red if the count is not equal to zero?

When the count equals 0, I don't want any effect on the notification box. However, when the count is not equal to zero, I want the notification box to turn red. I tried implementing this, but it's not working as expected. By not working, I mean n ...

Using jQuery to clear input text upon keyDown event

Currently, I have an input box with default text displayed: <input type="text" value="Enter Name"/> My goal is to have the text disappear once the user starts typing and have them input their desired text. I attempted to achieve this using the foll ...

Guide on enabling the scrollbar within a text area while utilizing the pointer-events: none property

After applying the CSS rule pointer-events: none to the text area, I noticed that the scrollbar was disabled. I need the scrollbar to remain enabled so that users can scroll and view the entire content, while still preventing editing within the textarea u ...

"Javascript's onClick event not working for multiple elements, only the first one

I am struggling to make my thumbnails open the larger images when clicked. It is only working for the first thumbnail, and I can't seem to figure out why. Here is the snippet of code I have been trying to work with: <script type="text/javascript" ...

Enabling and Disabling Input Fields Based on Selections in VueJS

Originally submitted on es.stackoverflow.com by José: I came across an example in JavaScript that works, but I'm struggling to implement it in vue.js. I've been attempting it for some time without success. Apologies for any inconvenience. < ...

The TypeScript compiler is generating node_modules and type declaration files in opposition to the guidelines outlined in the tsconfig.json file

For the past week, I've been trying to troubleshoot this issue and it has me completely puzzled. What's even more puzzling is that this app was compiling perfectly fine for months until this problem occurred seemingly out of nowhere without any c ...

Tips for updating parameters that are defined in a controller within a promise

Currently, I am developing a single page application using Angular and TypeScript. I am facing an issue with updating the parameter value (_isShowFirst) of the controller inside a promise function. It seems like nothing is recognized within the promise blo ...

Is the attribute of the label malfunctioning within an Angular directive?

As I delve into the world of angular directives, I have encountered success in many aspects. However, there is one minor issue that has been troubling me lately. Within my directive, I have set a for attribute to match the id of an input field. Strangely, ...

The Symfony API failed to generate a response

There seems to be a problem when trying to link the Symfony API with a React application. The API is not providing any response, even though it works fine when accessed directly through the link. ApiDirectURL Fetching this data from the React app is yiel ...

Having trouble with the Bootstrap dropdown? The unordered list isn't dropping down as expected. What could be the issue?

I am facing an issue with two dropdowns in my template. Both of them are not functioning properly, one with Thymeleaf attributes and the other without. I have not attempted to change the CSS properties as they were working fine before but now they do not ...