Reputation: 3843
I want to emit an event to the client when a long fucntion comes to an end. This will show a hidden div with a link - on the client side.
This is the approach i tested:
//server.js
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
require('./app/routes.js')(app, io);
//routes.js
app.post('/pst', function(req, res) {
var url = req.body.convo;
res.render('processing.ejs');
myAsyncFunction(url).then(result => {
console.log('Async Function completed');
socket.emit('dlReady', { description: 'Your file is ready!'});
//do some other stuff here
}).catch(err => {
console.log(err);
res.render('error.ejs');
})
});
I get this
ERROR: ReferenceError: socket is not defined
If i change the socket.emit() line to this:
io.on('connection', function(socket) {
socket.emit('dlReady', { description: 'Your file is ready!'});
});
Then i don't receive an error, but nothing happens at the client.
This is the client code:
<script>
document.querySelector('.container2').style.display = "none";
var socket = io();
socket.on('dlReady', function(data) { //When you receive dlReady event from socket.io, show the link part
document.querySelector('.container1').style.display = "none";
document.querySelector('.container2').style.display = "block";
});
</script>
Upvotes: 0
Views: 895
Reputation: 707328
This whole concept is likely a bit flawed. Let me state some facts about this environment that you must fully understand before you can follow what needs to happen:
res.render()
, the browser will close down the previous page and render the new page.res.render()
has Javascript in it, when that Javascript runs, it may or may not create a new socket.io connection to your server. In any case, that won't happen until some time AFTER the res.render()
is called as the browser has to receive the new page, parse it, then run the Javascript in it which has to then connect socket.io to your server again.socket.emit()
only on that particular socket. The server can never do this by creating some server-wide variable named socket
and using that. A multi-user server can never do that.So, my understanding of your problem is that you'd like to get a form POST from the client, return back to the client a rendered processing.ejs
and then sometime later, you'd like to communicate with that rendered page in the client via socket.io. To do that, the following steps must occur.
express-session
to do it for you. I'd suggest using express-session
because it will make the following steps easier and I will outline steps assuming you are using express-session
.io.on('connection', ...)
on your server that puts the socket
into the session object. Because the client can connect from multiple tabs, if you don't want that to cause trouble, you probably have to maintain an array of sockets in the session object.socket.on('disconnect', ...)
handler on your server that can remove a socket from the session object it's been stored in when it disconnects.app.post()
handler, when you are ready to send the dlready
message, you will have to find the appropriate socket
for that browser in the session object for that page and emit to that socket(s). If there are none because the page you rendered has not yet connected, you will have to wait for it to connect (this is tricky to do efficiently).If the POST request comes in from Javascript in the page rather than from a form post, then things are slightly simpler because the browser won't close the current page and start a new page and thus the current socket.io connection will stay connected. You could still completely change the page visuals using client-side Javascript if you wanted. I would recommend this option.
Upvotes: 1