2
votes

First time poster here. I am trying to put together a chatroom app using Flask-SocketIO and am having a hard time getting one tiny, but crucial, piece to work. When I call the emit method in the server and set the broadcast=True flag, the expected behavior is that it triggers the respective socket.on events on the client side for all users, including the sender. However, my code apparently only does so for all clients other than the sender. This is contrary to the documentation at https://flask-socketio.readthedocs.io/en/latest/, where it states:

When a message is sent with the broadcast option enabled, all clients connected to the namespace receive it, including the sender. When namespaces are not used, the clients connected to the global namespace receive the message.

I need for this to send the message and trigger the socket.on event for the sender as well as all other clients. Can anyone explain what I'm doing wrong here? Because it seems like such a basic feature that I must be missing something really obvious.

Server code:

import os
import requests

from flask import Flask, jsonify, render_template, request
from flask_socketio import SocketIO, emit, join_room, leave_room

app = Flask(__name__)
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
socketio = SocketIO(app)

channels = ['a', 'b', 'c', 'testing', 'abc', '123']
ch_msgs = {'a': ['testing', '1234', 'high five'], 'b': ['hello']}
msg_limit = 100

@app.route('/')
def index():
    return render_template('index.html')

@socketio.on('add channel')
def add(data):
    new_channel = data
    channels.append(new_channel)
    ch_msgs[new_channel] = list()

    emit('announce channel', new_channel, broadcast=True)

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0')

Javascript:

document.addEventListener('DOMContentLoaded', () => {

    var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port);

    socket.on('connect', () => {

        document.querySelector('#add_channel').onclick = () => {

            const new_channel = document.querySelector('#new_channel').value;

            socket.emit('add channel', new_channel);

        };


    });

    socket.on('announce channel', data => {

        const li = document.createElement('li');

        li.innerHTML = '#' + `${data}`;

        $('#channel_list').append(li);

    });
});

HTML/CSS snippet:

<h3>Chat Channels</h3>
<br>

<ul id='channel_list' style='list-style-type:none;'>
</ul>

<form class='channel'>
     <input type='text' id='new_channel' placeholder='add new channel'><input type='submit' id='add_channel' value='Add'>
</form>
1

1 Answers

1
votes

All clients in fact are receiving the message sent, including the sender, but the issue here is that the sender's page is refreshed as soon as the form is submitted, (which is the default behavior of forms) thus resulting in loss of all local data.

In order to prevent this, you need to use event.preventDefault() method. In your case, you may change the event handler for connect event like this:

socket.on('connect', () => {
    document.querySelector('#add_channel').onclick = event => {
        event.preventDefault();
        const textinput = document.querySelector('#new_channel')
        const new_channel = textinput.value;
        textinput.value = "";    // Clear input after value is saved
        socket.emit('add channel', new_channel);
    };
});