In the First part, we created files required to set up for our Nodejs server and completed the Nodejs server setup, also in the first part we did the AngularJs setup for the application. After completing all the setup for Real Time chatting app, we created Login & Registration page.In the second part, we created a chat list features and wrote methods to display chat list. In this part, we will create real-time chatting feature between two players.
Here we will complete two features listed below,
- We will fetch messages between two users.
- Sending Messages between users (Real-time chatting feature)
1. Fetching the messages between two users
So let’s start with the first point, so we will pick up from where we left in the last part and i.e. chat list feature. So the idea here is to click on any user displayed on chat list, should fetch the list of messages between logged in user and that user.
=>We will achieve that by passing the user Ids of those players.
=>We will register ang-click
function on the list of users as shown in below markup.
home.html:
<!-- Real Time chatting app @author Shashank Tiwari --> <!-- Chat list Markup starts --> <div class="col-md-4"> <div class="chat-list-container"> <p class="chat-list-heading"><i class="fa fa-list" aria-hidden="true"></i> <span >Chat list</span> </p> <div class="chat-list"> <ul class="list-group" ng-if="data.chatlist.length > 0"> <li class="list-group-item" ng-repeat="friend in data.chatlist" ng-click="selectFriendToChat(friend.id)" <!-- Added a ng-click() function --> ng-class="{'active':friend.id == data.selectedFriendId}" >{{friend.username}}</li> </ul> <div class="alert alert-info" ng-if="data.chatlist.length === 0"> <strong>No one is online to chat, ask someone to Login.</strong> </div> </div> </div> </div> <!-- Chat List Markup ends -->
Inside theselectFriendToChat()
function, we will do two things. First, we will highlight the user selected from the list and second, we will make the HTTP call to get the messages between users.
=>To do that we have to write a function inside the home controller, which will do both the things.
=>Open thehome.controller.js
and write down below function.
home.controller.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; $scope.selectFriendToChat = (friendId) => { /* * Highlighting the selected user from the chat list */ const friendData = $scope.data.chatlist.filter((obj) => { return obj.id === friendId; }); $scope.data.selectedFriendName = friendData[0]['username']; $scope.data.selectedFriendId = friendId; /** * This HTTP call will fetch chat between two users */ appService.getMessages(UserId, friendId).then( (response) => { $scope.$apply(() => { $scope.data.messages = response.messages; }); }).catch( (error) => { console.log(error); alert('Unexpected Error, Contact your Site Admin.'); }); }
When a client makes this HTTP call, on the server side we must have something to take care of this call. So we will write a route to handle this HTTP call also we will write the query to fetch messages from the database.
=>Open theroutes.js
file and write down the below code.
=>In the below code we are consuminggetMessages()
method ofHelper
class to fetch the messages from the database.
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; this.app.post('/getMessages',async (request,response) => { const userId = request.body.userId; const toUserId = request.body.toUserId; const messages = {} if (userId === '') { messages.error = true; messages.message = `userId cant be empty.`; response.status(200).json(messages); }else{ const result = await helper.getMessages( userId, toUserId); if (result === null) { messages.error = true; messages.message = `Internal Server error.`; response.status(500).json(messages); }else{ messages.error = false; messages.messages = result; response.status(200).json(messages); } } });
Now moving over to Helper class here, we have to write MySql query to fetch data from the database. The below is wrapped inside the async/await function as show below.
helper.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; async getMessages(userId, toUserId){ try { return await this.db.query( `SELECT id,from_user_id as fromUserId,to_user_id as toUserId,message FROM message WHERE (from_user_id = ? AND to_user_id = ? ) OR (from_user_id = ? AND to_user_id = ? )ORDER BY id ASC `, [userId, toUserId, toUserId, userId] ); } catch (error) { console.warn(error); return null; } }
2. Sending Messages between users (Real-time chatting feature)
Here I would like to divide this topic into two parts.The first part issending the messagesand the second will be thereceiving the messagesfrom the socket server. And we will learn both of them one by one.
1. Sending the messages
Now, this features completely relies on the socket Events. If server emits any event then the client will respond to it accordingly. If you are not new to socket programming then you must be aware of how things work here. But for those who don’t know much about it, I will explain here anyway.
=>So here we will implement a real-time chat between users by sending an event from the client.
=>When the server receives the emitted request from client then it responds back to the client to whom we are willing to send a message.
=>In our case, we will pass the socket id to server and server will emit the event only to that socket id.
=>Let’s start with the markup, Open thehome.htmland add the below markup to it,
home.html:
<!-- Real Time chatting app @author Shashank Tiwari --> <!-- Message Area Markup starts --> <div class="col-md-8"> <div class="message-container"> <p ng-show="data.selectedFriendId !== null" ? true : false > <i class="fa fa-envelope" aria-hidden="true"></i> <span class="message-heading"> Chat History With {{data.selectedFriendName}}</span> </p> <div class="message-list"> <ul class="message-thread"> <li ng-repeat="messagePacket in data.messages" ng-class="{ 'align-right' : alignMessage(messagePacket.fromUserId) } "> {{messagePacket.message}} </li> </ul> </div> <div class="message-text"> <textarea id="message" class="message form-control" placeholder="Type and hit Enter" ng-keydown="sendMessage($event)" ></textarea> </div> </div> </div> <!-- Message Area Markup ends -->
Explanation:
In the above markup, three important things are happening, which are listed below.
- First, when you select a user from chat list, we show a dialog asChat History With ####. Nothing complicated with it just anAngularJs
model
and that’s it. - Below to that, we will have a list of messages, which can be rendered using
data.messages
model usingng-repeat
. - As I explained in above, How wefetch messages from the serverby makingHTTP call.
- Now when we receive messages from the server by making HTTP call, we assign new messages to this
data.messages
model which renders the messages. - And at the end, we have we have
textarea
to write messages and we have set up akeydown
listener to send messages. - After writing messages, when user will press enter button message will be sent through socket.io.
We wrote markup to send messages, but to make work them we’ll have to write some AngularJs. For the above markup, we already wrote the AngularJs for them in the previous section. Inside theselectFriendToChat()
we have written the half of the above markup. So we will focus on only sending messages part. Open thehome.controller.jsand write down the below code,
home.controller.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; $scope.sendMessage = (event) => { if (event.keyCode === 13) { let toUserId = null; let toSocketId = null; /* Fetching the selected User from the chat list starts */ let selectedFriendId = $scope.data.selectedFriendId; if (selectedFriendId === null) { return null; } friendData = $scope.data.chatlist.filter((obj) => { return obj.id === selectedFriendId; }); /* Fetching the selected User from the chat list ends */ /* Emmiting socket event to server with Message, starts */ if (friendData.length > 0) { toUserId = friendData[0]['id']; toSocketId = friendData[0]['socketid']; let messagePacket = { message: document.querySelector('#message').value, fromUserId: UserId, toUserId: toUserId, toSocketId: toSocketId }; $scope.data.messages.push(messagePacket); appService.socketEmit(`add-message`, messagePacket); document.querySelector('#message').value = ''; appService.scrollToBottom(); }else { alert('Unexpected Error Occured,Please contact Admin'); } /* Emmiting socket event to server with Message, ends */ } }
Explanation:
In the above function, we are doing three main things,
- First, here we are extracting the selected friend’s information to send messages.
- Then we create a message packet and send it to the socket server also we push the message packet to the
data.messages
model to render it on the screen. - Then we scroll the div which displays the messages to the bottom.
I assume that you understand the purpose of this block and if you have any questions please comment below, I’ll help in that. Now it’s time to write server-side socket events.
=>Now we will write a socket event in order to listen to messages on the server side and accordingly will send a response back to the server.
=>Once the server receives the event it will store messages to the database, by executing the MySql queries.
=>In the below code, we are callinginsertMessages()
method of the Helper class, which will store the messages into MySql database.
=>Then we send message data to the corresponding user by emitting the socket event. Open thesocket.jsfile and write down the below code,
socket.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; /** * send the messages to the user */socket.on('add-message', async (data) => { if (data.message === '') { this.io.to(socket.id).emit(`add-message-response`,`Message cant be empty`); }else if(data.fromUserId === ''){ this.io.to(socket.id).emit(`add-message-response`,`Unexpected error, Login again.`); }else if(data.toUserId === ''){ this.io.to(socket.id).emit(`add-message-response`,`Select a user to chat.`); }else{ let toSocketId = data.toSocketId; const sqlResult = await helper.insertMessages({ fromUserId: data.fromUserId, toUserId: data.toUserId, message: data.message }); this.io.to(toSocketId).emit(`add-message-response`, data); } });
Open thehelper.jsfile and write down the below code. In the below code, we execute MySql insert query to store MySQL data nothing more than that.
helper.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; async insertMessages(params){ try { return await this.db.query( "INSERT INTO message (`from_user_id`,`to_user_id`,`message`) values (?,?,?)", [params.fromUserId, params.toUserId, params.message] ); } catch (error) { console.warn(error); return null; } }
2. Receivingthe messages
In this small section, we will write the socket event handler for the receiving the socket event on the client side and which will be very easy. Open thehome.controller.jsand write down below code we will do listed things below,
=>We will userscoket.on
a method to handle the socket event and receive the messages.
=>After receiving the messages we will display them usingdata.messages
model.
=> You will add this code inside thehome.controller.js, just below to the chat list code.
home.controller.js:
/** * Real Time chatting app * @author Shashank Tiwari */ 'use strict'; /* * This eventt will display the new incmoing message */appService.socketOn('add-message-response', (response) => { $scope.$apply( () => { if (response && response.fromUserId == $scope.data.selectedFriendId) { $scope.data.messages.push(response); appService.scrollToBottom(); } }); });
Final thoughts
Now you know, how to create a private chatting application in AngularJs with minimum complexity, for now, that’s the end of this series. If you want toreport an issue, you can use GitHub for that, I have uploaded thecode to the GitHub. Using GitHub will be very easy for all of us to track all the issues.
Alos, If you like this article consider sharing this on your social account with other people as well. You can suggest or request an article on any topic I would love write it for you.
If you have any suggestion or Question let me know in the below comment box and If you like this article share with others.
Hello! I want to integrate a chat on my site.Site placed on the YII framework. What do you advise ?
Hi!
please check demo, not working!!
This Demo not work
I’m getting the code instead of the query result in the home page after login.
{{send_to_user_name==” ? ‘Select User to Chat’: send_to_user_name}}
All the .js & css are on the right directory.
Could you help me with that?
https://uploads.disquscdn.com/images/9eb1cf6c51f73bea2b20d42d3a24bc267a13647c3d19ab7e5bea396094125144.png
hii Javier,
Make sure you don’t have any errors in js file,open the console try to resolve those error.
For some reason I can’t open the zip file. Can you please zip the file again? thanks.
nice one. that i wanted man. 🙂
@ShankyTtiwari:disqus
Thank you 😀
whenever i refresh socket.id is changed ? why?
Useful links for you.
1. http://stackoverflow.com/questions/20260170/handle-browser-reload-socket-io
2. http://stackoverflow.com/questions/9528845/how-to-avoid-create-a-new-socket-connection-in-socket-io-after-html-page-refresh
@ShankyTtiwari:disqus many time socket.id is generating same id for multiple users why? in nodejs
many time socket.id is generating same id for multiple users That’s very Rear in my knowledge. If you are thinking to use socket id as unique user id then please don’t do that.
Some Useful links for you.
1. http://stackoverflow.com/questions/20962970/how-unique-is-socket-id
2. http://stackoverflow.com/questions/15989514/can-you-rely-on-socket-id-as-a-uid
Can we send files in this chat application?
Yes,we can. If I have to do that I would do that something like this,
1. I will upload files on the server.
2.Then in messages I will send the path of the file with the file extension and take appropriate action (for ex, showing Image/video or audio tag)
Hope this helps you.