Reputation: 105
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
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
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