Description:
I am currently developing a chat application using node.js and socket.io... What my problem is ... when ever user X send a message to user Y or vice versa i am storing in mongo DB ... so i want to show the count of message received from Y to User X and count of messages received from X to Y as below shown image.
Problem: If i do console.log it is working but if i am appending the count of messages to html then it is showing last occurrence only
Here is the screen shot which contains two online users with last occurrence messages count..
Below is the client side Java script code.
READ THE COMMENTS IN THE BELOW CODE TO UNDERSTAND
$(function() {
var socket = io('/chat');
var username = $('#user').val();
var noChat = 0; //setting 0 if all chats histroy is not loaded. 1 if all chats loaded.
var msgCount = 0; //counting total number of messages displayed.
var oldInitDone = 0; //it is 0 when old-chats-init is not executed and 1 if executed.
var roomId; //variable for setting room.
var toUser;
//passing data on connection.
socket.on('connect', function() {
socket.emit('set-user-data', username);
// setTimeout(function() { alert(username+" logged In"); }, 500);
socket.on('broadcast', function(data) {
document.getElementById("hell0").innerHTML += '<li>' + data.description + '</li>';
// $('#hell0').append($('<li>').append($(data.description).append($('<li>');
$('#hell0').scrollTop($('#hell0')[0].scrollHeight);
});
}); //end of connect event.
var to;
var tocount;
var fromcount;
socket.on('countynew', function(data) {
console.log(data.rec);
console.log(data.count);
console.log(data.fro);
to = data.rec;
});
//receiving online users stack from server node js.
socket.on('onlineStack', function(stack) {
$('#list').empty();
$('#list').append($('<li>').append($('<button id="ubtn" class="btn btn-danger btn-block btn-lg"></button>').text("Group").css({
"font-size": "18px"
})));
var txt_count;
var totalOnline = 0;
//FOR LOOP TO GET ALL THE ONLINE USERS
for (let user in stack) {
//listing all users.
if (user != username && stack[user] == "Online") {
// totalOnline variable count counts how many users are in online
totalOnline++
var fuser = user;
var fusern = username;
var tryit;
// From here i am sending onlineusers list and owner (owner is the perosn who is using this script) to server using socket.io
socket.emit('sendinguserandowner', {
onlineuser: fuser,
owner: fusern
});
//datahit contains whom sent, how many messages sent and who send
socket.on('hitback', function(datahit) {
tryit = datahit;
//datahit.to contains your user name (The person who is currently using this script: owner) // CONSIDER X USING and he
//datahit.to conatins count of messages recieved from datahit.from
//datahit.from contains online users for X // Y, Z, A, B....
console.log(datahit.to + " You recieved " + datahit.count + " from " + datahit.from);
//HERE IS THE PROBLEM
//HERE IS THE PROBLEM
//HERE IS THE PROBLEM
//HERE IS THE PROBLEM
if (datahit.from==fuser) {
$('.county')
.text(datahit.count) // EVERY TIME IT RETURNS LAST OCCORANCE VALUE example : if for loop iterating 3 times like 0,1,2 i am able to see 0,1,2 if i do console.log but if i append to HTML i am getting 2 only
.css({
"float": "center",
"color": "#000",
"font-size": "25px"
});
}
//UP TO HERE IS THE PROBLEM
//UP TO HERE IS THE PROBLEM
//UP TO HERE IS THE PROBLEM
//UP TO HERE IS THE PROBLEM
});
var txt_count = $('<span class="county"></span>')
.text("-")
.css({
"float": "center",
"color": "#000",
"font-size": "25px"
});
var txt1 = $('<button id="ubtn" class="btn btn-success btn-md">').text(user).css({ // HERE I AM APPENDING ONLINE USER'S NAME TO BUTTON
"font-size": "18px"
});
//console.log(user+" "+username); // to view in browser console
var txt2 = $('<span class="badge"></span>').text("*" + stack[user]).css({ // HERE IS THE STATUS OF ONLINE USER WHETHER HE/SHE is ONLINE OR OFFLINE
"float": "right",
"color": "#009933",
"font-size": "18px"
});
$('#list').append($('<li>').append(txt1, txt2, txt_count));// ITERATE BY ABOVE FOR LOOP AND APPAEND ONLINE USER NAMES AND THEIR STATUS TO BUTTONS
}
$('#totalOnline').text(totalOnline);
} //END OF THE FOR.
$('#scrl1').scrollTop($('#scrl1').prop("scrollHeight"));
}); //end of receiving onlineStack event.
//on button click function.
$(document).on("click", "#ubtn", function() {
//empty messages.
$('#messages').empty();
$('#typing').text("");
msgCount = 0;
noChat = 0;
oldInitDone = 0;
//assigning friends name to whom messages will send,(in case of group its value is Group).
toUser = $(this).text();
socket.emit('readed', {
readed: toUser
});
//showing and hiding relevant information.
$('#frndName').text(toUser);
$('#initMsg').hide();
$('#chatForm').show(); //showing chat form.
$('#sendBtn').hide(); //hiding send button to prevent sending of empty messages.
//assigning two names for room. which helps in one-to-one and also group chat.
if (toUser == "Group") {
var currentRoom = "Group-Group";
var reverseRoom = "Group-Group";
} else {
var currentRoom = username + "-" + toUser;
var reverseRoom = toUser + "-" + username;
}
//event to set room and join.
socket.emit('set-room', {
name1: currentRoom,
name2: reverseRoom
});
}); //end of on button click event.
//event for setting roomId.
socket.on('set-room', function(room) {
//empty messages.
$('#messages').empty();
$('#typing').text("");
msgCount = 0;
noChat = 0;
oldInitDone = 0;
//assigning room id to roomId variable. which helps in one-to-one and group chat.
roomId = room;
console.log("roomId : " + roomId);
//event to get chat history on button click or as room is set.
socket.emit('old-chats-init', {
room: roomId,
username: username,
msgCount: msgCount
});
}); //end of set-room event.
//on scroll load more old-chats.
$('#scrl2').scroll(function() {
if ($('#scrl2').scrollTop() == 0 && noChat == 0 && oldInitDone == 1) {
$('#loading').show();
socket.emit('old-chats', {
room: roomId,
username: username,
msgCount: msgCount
});
}
}); // end of scroll event.
//listening old-chats event.
socket.on('old-chats', function(data) {
if (data.room == roomId) {
oldInitDone = 1; //setting value to implies that old-chats first event is done.
if (data.result.length != 0) {
$('#noChat').hide(); //hiding no more chats message.
for (var i = 0; i < data.result.length; i++) {
//styling of chat message.
var chatDate = moment(data.result[i].createdOn).format("MMMM Do YYYY, hh:mm:ss a");
var txt1 = $('<span></span>').text(data.result[i].msgFrom + " : ").css({
"color": "#006080"
});
var txt2 = $('<span></span>').text(chatDate).css({
"float": "right",
"color": "#a6a6a6",
"font-size": "16px"
});
var txt3 = $('<p></p>').append(txt1, txt2);
var txt4 = $('<p></p>').text(data.result[i].msg).css({
"color": "#000000"
});
//showing chat in chat box.
$('#messages').prepend($('<li>').append(txt3, txt4));
msgCount++;
} //end of for.
// $('#county').text(msgCount);
console.log(msgCount);
} else {
$('#noChat').show(); //displaying no more chats message.
noChat = 1; //to prevent unnecessary scroll event.
}
//hiding loading bar.
$('#loading').hide();
//setting scrollbar position while first 5 chats loads.
if (msgCount <= 5) {
$('#scrl2').scrollTop($('#scrl2').prop("scrollHeight"));
}
} //end of outer if.
}); // end of listening old-chats event.
// keyup handler.
$('#myMsg').keyup(function() {
if ($('#myMsg').val()) {
$('#sendBtn').show(); //showing send button.
socket.emit('typing');
} else {
$('#sendBtn').hide(); //hiding send button to prevent sending empty messages.
}
}); //end of keyup handler.
//receiving typing message.
socket.on('typing', function(msg) {
var setTime;
//clearing previous setTimeout function.
clearTimeout(setTime);
//showing typing message.
$('#typing').text(msg);
//showing typing message only for few seconds.
setTime = setTimeout(function() {
$('#typing').text("");
}, 3500);
}); //end of typing event.
//sending message.
$('form').submit(function() {
socket.emit('chat-msg', {
msg: $('#myMsg').val(),
msgTo: toUser,
date: Date.now()
});
console.log("2. TO:" + toUser + " Message is:" + $('#myMsg').val() + " Line 202 in ScriptForChat file")
$('#myMsg').val("");
$('#sendBtn').hide();
return false;
}); //end of sending message.
//receiving messages.
unread = 0;
socket.on('chat-msg', function(data) {
unread++;
//styling of chat message.
var chatDate = moment(data.date).format("MMMM Do YYYY, hh:mm:ss a");
var txt1 = $('<span></span>').text(data.msgFrom + " : ").css({
"color": "#006080"
});
var txt2 = $('<span></span>').text(chatDate).css({
"float": "right",
"color": "#a6a6a6",
"font-size": "16px"
});
var txt3 = $('<p></p>').append(txt1, txt2);
var txt4 = $('<p></p>').text(data.msg).css({
"color": "#000000"
});
console.log("2. From:" + data.msgFrom + " Message is:" + data.msg)
//showing chat in chat box.
$('#messages').append($('<li>').append(txt3, txt4));
msgCount++;
console.log(msgCount);
$('#typing').text("");
$('#scrl2').scrollTop($('#scrl2').prop("scrollHeight"));
}); //end of receiving messages.
//on disconnect event.
//passing data on connection.
socket.on('disconnect', function() {
//showing and hiding relevant information.
$('#list').empty();
$('#messages').empty();
$('#typing').text("");
$('#frndName').text("Disconnected..");
$('#loading').hide();
$('#noChat').hide();
$('#initMsg').show().text("...Please, Refresh Your Page...");
$('#chatForm').hide();
msgCount = 0;
noChat = 0;
}); //end of connect event
}); //end of function
Below is the SERVER SIDE NODE JS FILE WITH SOCKET.IO
var socketio = require('socket.io');
var mongoose = require('mongoose');
var events = require('events');
var _ = require('lodash');
var eventEmitter = new events.EventEmitter();
//adding db models
require('../app/models/user.js');
require('../app/models/chat.js');
require('../app/models/room.js');
//using mongoose Schema models
var userModel = mongoose.model('User');
var chatModel = mongoose.model('Chat');
var roomModel = mongoose.model('Room');
//reatime magic begins here
module.exports.sockets = function (http) {
io = socketio.listen(http);
//setting chat route
var ioChat = io.of('/chat');
var userStack = {};
var oldChats, sendUserStack, setRoom;
var userSocket = {};
//socket.io magic starts here
ioChat.on('connection', function (socket) {
console.log("socketio chat connected.");
//function to get user name
socket.on('set-user-data', function (username) {
console.log(username + " logged In");
//HERE IS THE MAIN CODE WHICH WILL EXECUTE WHEN sendinguserandowner emits from CLIENT.JS
socket.on('sendinguserandowner', function (data) {
// Here using mongo i am retriving count of messages
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
MongoClient.connect(url, function (err, db) {
if (err) throw err;
var dbo = db.db("rio_chat");
dbo.collection("chats").find({
msgFrom: data.onlineuser,
msgTo: data.owner,
unread: "1"
}).count(function (err, result) {
if (err) throw err;
//DATAHIT IN CLIENT SIDE IS SAME AS HERE but this is for server side console
console.log(data.owner + " You recieved " + result + " from " + data.onlineuser);
// HERE I AM HITTING BACK TO BROWSER
socket.emit('hitback', {
to: data.owner,
count: result,
from: data.onlineuser
});
db.close();
});
});
});
//storing variable.
socket.username = username;
userSocket[socket.username] = socket.id;
socket.broadcast.emit('broadcast', {
description: username + ' Logged In'
});
//getting all users list
eventEmitter.emit('get-all-users');
//sending all users list. and setting if online or offline.
sendUserStack = function () {
for (i in userSocket) {
for (j in userStack) {
if (j == i) {
userStack[j] = "Online";
}
}
}
//for popping connection message.
ioChat.emit('onlineStack', userStack);
} //end of sendUserStack function.
}); //end of set-user-data event.
//setting room.
socket.on('set-room', function (room) {
//leaving room.
socket.leave(socket.room);
//getting room data.
eventEmitter.emit('get-room-data', room);
//setting room and join.
setRoom = function (roomId) {
socket.room = roomId;
console.log("roomId : " + socket.room);
socket.join(socket.room);
ioChat.to(userSocket[socket.username]).emit('set-room', socket.room);
};
}); //end of set-room event.
//emits event to read old-chats-init from database.
socket.on('old-chats-init', function (data) {
eventEmitter.emit('read-chat', data);
});
//emits event to read old chats from database.
socket.on('old-chats', function (data) {
eventEmitter.emit('read-chat', data);
});
//sending old chats to client.
oldChats = function (result, username, room) {
ioChat.to(userSocket[username]).emit('old-chats', {
result: result,
room: room
});
}
//showing msg on typing.
socket.on('typing', function () {
socket.to(socket.room).broadcast.emit('typing', socket.username + " : is typing...");
});
socket.on('readed', function (data) {
console.log("TO : " + data.readed + " From : " + socket.username + "");
});
//for showing chats.
socket.on('chat-msg', function (data) {
//emits event to save chat to database.
eventEmitter.emit('save-chat', {
msgFrom: socket.username,
msgTo: data.msgTo,
msg: data.msg,
room: socket.room,
unread: 1,
date: data.date
});
//emits event to send chat msg to all clients.
ioChat.to(socket.room).emit('chat-msg', {
msgFrom: socket.username,
msg: data.msg,
date: data.date
});
});
//for popping disconnection message.
socket.on('disconnect', function () {
console.log(socket.username + " logged out");
socket.broadcast.emit('broadcast', {
description: socket.username + ' Logged out'
});
console.log("chat disconnected.");
_.unset(userSocket, socket.username);
userStack[socket.username] = "Offline";
ioChat.emit('onlineStack', userStack);
}); //end of disconnect event.
}); //end of io.on(connection).
//end of socket.io code for chat feature.
//database operations are kept outside of socket.io code.
//saving chats to database.
eventEmitter.on('save-chat', function (data) {
// var today = Date.now();
var newChat = new chatModel({
msgFrom: data.msgFrom,
msgTo: data.msgTo,
msg: data.msg,
room: data.room,
unread: 1,
createdOn: data.date
});
newChat.save(function (err, result) {
if (err) {
console.log("Error : " + err);
} else if (result == undefined || result == null || result == "") {
console.log("Chat Is Not Saved.");
} else {
console.log("Chat Saved.");
//console.log(result);
}
});
}); //end of saving chat.
//reading chat from database.
eventEmitter.on('read-chat', function (data) {
chatModel.find({})
.where('room').equals(data.room)
.sort('-createdOn')
.skip(data.msgCount)
.lean()
.limit(5)
.exec(function (err, result) {
if (err) {
console.log("Error : " + err);
} else {
//calling function which emits event to client to show chats.
oldChats(result, data.username, data.room);
}
});
}); //end of reading chat from database.
//listening for get-all-users event. creating list of all users.
eventEmitter.on('get-all-users', function () {
userModel.find({})
.select('username')
.exec(function (err, result) {
if (err) {
console.log("Error : " + err);
} else {
//console.log(result);
for (var i = 0; i < result.length; i++) {
userStack[result[i].username] = "Offline";
}
//console.log("stack "+Object.keys(userStack));
sendUserStack();
}
});
}); //end of get-all-users event.
//listening get-room-data event.
eventEmitter.on('get-room-data', function (room) {
roomModel.find({
$or: [{
name1: room.name1
}, {
name1: room.name2
}, {
name2: room.name1
}, {
name2: room.name2
}]
}, function (err, result) {
if (err) {
console.log("Error : " + err);
} else {
if (result == "" || result == undefined || result == null) {
var today = Date.now();
newRoom = new roomModel({
name1: room.name1,
name2: room.name2,
lastActive: today,
createdOn: today
});
newRoom.save(function (err, newResult) {
if (err) {
console.log("Error : " + err);
} else if (newResult == "" || newResult == undefined || newResult == null) {
console.log("Some Error Occured During Room Creation.");
} else {
setRoom(newResult._id); //calling setRoom function.
}
}); //end of saving room.
} else {
var jresult = JSON.parse(JSON.stringify(result));
setRoom(jresult[0]._id); //calling setRoom function.
}
} //end of else.
}); //end of find room.
}); //end of get-room-data listener.
//end of database operations for chat feature.
//to verify for unique username and email at signup.
//socket namespace for signup.
var ioSignup = io.of('/signup');
var checkUname, checkEmail; //declaring variables for function.
ioSignup.on('connection', function (socket) {
console.log("signup connected.");
//verifying unique username.
socket.on('checkUname', function (uname) {
eventEmitter.emit('findUsername', uname); //event to perform database operation.
}); //end of checkUname event.
//function to emit event for checkUname.
checkUname = function (data) {
ioSignup.to(socket.id).emit('checkUname', data); //data can have only 1 or 0 value.
}; //end of checkUsername function.
//verifying unique email.
socket.on('checkEmail', function (email) {
eventEmitter.emit('findEmail', email); //event to perform database operation.
}); //end of checkEmail event.
//function to emit event for checkEmail.
checkEmail = function (data) {
ioSignup.to(socket.id).emit('checkEmail', data); //data can have only 1 or 0 value.
}; //end of checkEmail function.
//on disconnection.
socket.on('disconnect', function () {
console.log("signup disconnected.");
});
}); //end of ioSignup connection event.
//database operations are kept outside of socket.io code.
//event to find and check username.
eventEmitter.on('findUsername', function (uname) {
userModel.find({
'username': uname
}, function (err, result) {
if (err) {
console.log("Error : " + err);
} else {
//console.log(result);
if (result == "") {
checkUname(1); //send 1 if username not found.
} else {
checkUname(0); //send 0 if username found.
}
}
});
}); //end of findUsername event.
//event to find and check username.
eventEmitter.on('findEmail', function (email) {
userModel.find({
'email': email
}, function (err, result) {
if (err) {
console.log("Error : " + err);
} else {
//console.log(result);
if (result == "") {
checkEmail(1); //send 1 if email not found.
} else {
checkEmail(0); //send 0 if email found.
}
}
});
}); //end of findUsername event.
return io;};