William Sheppard
William Sheppard

Reputation: 105

Socket IO broadcasting to room is not functioning correctly

If this is a vague question, please let me know, so that I can specify. I really want to get around this stump.

I have read several cheat sheets regarding how to properly broadcast a message to a client room. My reference is: https://github.com/socketio/socket.io/blob/master/docs/emit.md.

To describe my problem: The chat page comes up with the send button correctly, however as soon as I click send, nothing is ever sent.

The interesting thing, is that whenever I am not using rooms, and just use the default namespace, I can get messages.

Any idea on what is going on? Thank you!!

server.js

io.on('connection', function(socket) {
    global.rooms = 'room1';
    socket.on('subscribe', function(room) {
        socket.join(rooms);
        console.log(socket.id + 'joining room', rooms)
    })
    socket.on('chat', function(data) {
        io.to(rooms).emit('chat', data);
  })
})

chat.jade

extends layout

block content

 h2.page-header Chat Page
 div(id='the-chat')
  div(id='chat-window')
   div(id='output')
  input(id='handle', type='text', value = user.name, style= 'width: 0px; visibility: hidden;')
  input(id='message', type='text', placeholder='message')
  button(id='send' value='Send') Send

  //imports the socket.io functionality on the client side for the chat.jade application
  script(src="/socket.io/socket.io.js")

  script.

    //variable created that mirrors connection made in the backend

    //matches the connection made in the server side
    var socket = io.connect('http://localhost:3000')

    //Query dom
    var message = document.getElementById('message')
    var handle = document.getElementById('handle')
    var btn = document.getElementById('send')
    var output = document.getElementById('output')

    //emit events
    btn.addEventListener('click', function() {
      socket.emit('chat', {
        message: message.value,
        handle: handle.value
      })
    })


    socket.on('chat', function(data) {
      output.innerHTML += '<p><strong>' + data.handle + ': </strong>' + data.message + '</p>';
      document.getElementById('message').value = "";
    })

Home.jade

extends layout


block content

    h2.page-header(style = "text-align: center;").
        Home Page

    if (user.isTutor)
        b(style = "text-align: center;")
            form(method='post', action = '/home/available')
                input.btn.btn-primary(type = 'submit',name='isAvailable', value = 'Available', id = 'button4')
            form(method='post', action = '/home/unavailable')
                input.btn.btn-primary(type = 'submit',name='isUnavailable', value = 'Unavailable', id = 'button5')  
    script(src="/socket.io/socket.io.js")
    script.
        var btn = document.getElementById('button4')
        //var space = '#{user.room}'
        var socket = io.connect()
        btn.addEventListener('click', function() {
            socket.emit('subscribe', 'room1')
        })

    div(id = 'magic')
        form(method='get')
            if (user.hasApplied)
                input.btn.btn-primary(type = 'submit', onclick = "javascript: form.action = '/findatutor';" name='find', value = 'Find a Tutor', class = 'middle', id = 'button7')

            else if (user.hasApplied == false)
                input.btn.btn-primary(type = 'submit', onclick = "javascript: form.action = '/findatutor';" name='find', value = 'Find a Tutor', id = 'button1')
                input.btn.btn-primary(type = 'submit', onclick = "javascript: form.action = '/apply';"  name='become', value = 'Become a Tutor', id = 'button2')

Home.js

router.post('/available', ensureAuthenticated, (req,res,next) => {
    var io = res.locals['socketio']
    db.collection('DefaultUser').update({_id: req.user._id}, {$set: {isAvailable: true}});
    res.redirect('../chat')
})

Upvotes: 1

Views: 441

Answers (3)

Yilmaz
Yilmaz

Reputation: 49182

The problem is you did not specify where to render the messages. As I understood, you have no problem creating rooms, so I will explain step by step how to handle after that point.

According to your code this is the communication between server and client for sending messages

//server.js
 socket.on('chat', function(data) {
        io.to(rooms).emit('chat', data);
  })
//chat.jade
btn.addEventListener('click', function() {
      socket.emit('chat', {
        message: message.value,
        handle: handle.value
      })
    })

First client is sending the message (typing the input box) to the server and when server receives it, it has to send the same message to all other clients. once clients receive this message, clients have to figure out how to display it. But when server sends the received message, then you have to initiate a new event. let's call it display. so your code should be like this:

//server.js
//i always use arrow functions, but I will follow along your code
     socket.on('chat', function(data) { 
            io.to(rooms).emit('display', data);
      })

Now your client should be listening for this event and should be handling where to display it:

//chat.jade

socket.on('display', (data) => {
    const displayedMessage = pug.render(messageTemplate, {
        message: data.message,
    })
    $messages.insertAdjacentHTML('beforeend', displayedMessage)
})

Since Jade has been renamed to pug, i used pug here. So i will render {message: data.message} into html in a script tag then placed it into DOM ELEMENT $message.

I am not sure where you want to render handle:handle.value i will just show how to display message. similarly, you can handle it.

Now what are messageTemplate, $messages and insertAdjacentHTML()?

create a div tag and a script tag in your html

//this is where you are gonna display the message
<div id="messages" class="chat__messages"></div>

<!-- template messages -->
    <script id="message-template" type="text/html">
      <div>
          <p>{{message}}</p>
      </div>
    </script>

//chat.jade

const $messages = document.getElementById("messages");
const messageTemplate = document.getElementById("message-template").innerHTML;

The insertAdjacentHTML() method inserts a text as HTML, into a specified position. you can get more explanation and examples here:

https://www.w3schools.com/jsref/met_node_insertadjacenthtml.asp

socket io code looks long and complicated but if you know the logic and move step by step it will easy to implement it.

Upvotes: 1

Afrophysics
Afrophysics

Reputation: 599

Missing this under global.rooms = 'room1';

var rooms = global.rooms

Longer Answer: At least what I can see, you've added "rooms" as a property on the global object (idk where 'global' itself is defined, but if it's not throwing an error, I'm assuming you defined it above). While it's a property, the variable 'rooms' that you're using as a namespace isn't defined at the time you're calling it, so it doesn't know where to emit the message.

Even more answer: Also, if you're intending to add additional rooms to global.rooms, I think you might want to use a hashlist to store them, so that you can easily access them as global.rooms[room], as well as easily add new rooms to the list ie global.rooms[room.name] = room

Upvotes: 0

Kevin Tran
Kevin Tran

Reputation: 147

Try

io.in(rooms).emit('chat', data);

Upvotes: 0

Related Questions