1

The issue I am running into with angularjs and socketio chat app is that when sending a message to another user the event handler for the displaying the message gets triggered more than once so the same message appears on the screen more than once which I only want it to display the message once. Could someone explain why this is happening and how to fix this issue.

Here is my client side code. I use ngRoute to change pages and I am using a service to preserve data when switching pages.

     // This method populates the chatbox on startup
     // Also it is emitted to on server side to display a new message
     socket.on("populateMessagesArchived", function (message) {
         $scope.tempArray = [message[0], message[1], message[2]];
         $scope.messages.push($scope.tempArray);
         $scope.$apply();
         $scope.tempArray = [];
         $scope.message="";
     });


     // When a users sends a message, this is invoked
     // this function gets the roomNum and message where roomNum corresponds to the roomNum where user sent message
     $scope.getMessage = function(roomNum, message) {
       $scope.tempArray = [roomNum, message, $scope.username];
       $scope.messages.push($scope.tempArray);
       socket.emit("storeMessagesInDatabase", {"uuid": $scope.uuid, "message": message, "roomNum": roomNum, "username": $scope.username});
       var element = document.getElementById('msgpane');
       element.scrollTop = element.scrollHeight;      
       $scope.tempArray = [];
       $scope.message="";
     };

Server Code: Basically adds the messages to a postgresql database. And handles login checking and registration. But I do not think the problem lies here. What I have noticed is when I switch pages another socketio connection is made. The amount of socketio connections corresponds to how many messages get printed out. But I am not sure how to solve this problem. Any help would be greatly appreciated.

@socketio.on('userLoggedIn', namespace='/iss')
def loggedIn(user):        
    userData = user
    connect = connectToDB()
    cursor = connect.cursor(cursor_factory=psycopg2.extras.DictCursor)
    cursor.execute("""select uuid, username from users WHERE username = %s AND password = crypt(%s, password);""", (userData['username'], userData['password']))
    #query1 = cursor.mogrify("""select * from users WHERE username = %s AND password = 'crypt(%s, password)';""", (userData['username'], userData['password']))
    query = cursor.fetchone()
    if query is not None:
        # Here we get the messages from the database and pass them to client side
        tempArray = retrieveMessagesFromDB()
        print tempArray
        emit('userAuthorized', query["uuid"], namespace='/iss')

        for message in tempArray:
            // emitted to client side to populate the chat room on login of a user
            emit("populateMessagesArchived", message, namespace='/iss')  
    else:
        emit('userNotAuthorized', namespace='/iss')

#
# retrieves the messages from the database to populate the chat rooms
#
def retrieveMessagesFromDB():
    connect = connectToDB()
    cursor = connect.cursor(cursor_factory=psycopg2.extras.DictCursor)
    cursor.execute("""select messages.room_num, messages.message, users.username from users join messages on users.uuid = messages.uuid;""")
    query = cursor.fetchall()
    return query

#
# storeMessagesInDatabase - stores messages in the database
#
@socketio.on('storeMessagesInDatabase', namespace='/iss')
def storeMessagesInDatabase(userInfo):
    # userInfo is Json and we set it equal to tempDict
    tempDict=userInfo
    tempArray=[]
    tempArray.append(tempDict["roomNum"])
    tempArray.append(tempDict["message"])
    tempArray.append(tempDict["username"])
    connect = connectToDB()
    cursor = connect.cursor()

    try:
        cursor.execute("""insert into messages (uuid, message, room_num) values (%s, %s, %s);""", (str(tempDict["uuid"]), tempDict["message"], str(tempDict["roomNum"])))
    except:
        connect.rollback()
    connect.commit()   
    # Messages emitted back to client to be outputted on screen
    emit("populateMessagesArchived", tempArray, namespace='/iss', broadcast=True)
    tempArray=[]
sebenalern
  • 2,515
  • 3
  • 26
  • 36

1 Answers1

0

The way I solved my problem was to use angular-socket-io library. Which provides a forward() function to stop the duplication of event handlers which solves the problem of messages being repeated. Also now that I understand MPA destroy sockets on page switch and SPA do not. I would recommend placing the socketio code in a higher level module that will only be called once. See here for more of an explanation:

https://stackoverflow.com/a/36223423/3103677

Community
  • 1
  • 1
sebenalern
  • 2,515
  • 3
  • 26
  • 36