简体   繁体   中英

socket.io emit() doesn't work when added to button click event

My web page in short does the following:

  1. establishes a socket using socket.io and through that socket some data comes.
  2. Based on this data, rows in a table are created. Each row contains a button.
  3. The function of this button would be to send some data back through the socket.

Server code:

io = require('socket.io').listen(this.server);
io.of('/iot').use(onWSAuthorize);

function onWSAuthorize(socket, next) {
    socket.on('device_activate', function (msg) {
        console.log('device_activate received');
        onDeviceActivate(msg, socket)
    });
}

Client side:

var socket = io('/iot');
socket.on('device', setValue);

    function setValue(msg) {
        devArdID = msg.ardid + "_" + msg.devid;

        if (document.getElementById(devArdID) == null) {
            if (!msg.activated) { /* only put a device if it is not "Activated" */
                devArdID = msg.ardid + "_" + msg.devid;
                trDevName = '<tr id="' + devArdID + '" class="w3-hover-grey"><td>' + devTypeGetName(msg.devType) + '</td>';
                trActions = '<td><button id="' + devArdID + '_activate" class="small green">Activate</button></td></tr>'

                $("#devices").append(trDevName + trActions);
                $("#" + devArdID + "_activate").click(function() {
                    console.log('test');
                    socket.emit('device_activate', {my : 'test'});
                });
                //socket.emit('device_activate', {my : 'test'});
            }
        } else {
            /* the device already reported, structre needs to be filled in with new data */
            updateDeviceStatus(msg);
        }
    }     

Now when I execute the above client code and the setValue() gets triggered by incoming "device" event emitted by the server, row is added to the table - this row contains a button. When I press the button it's anonymous function gets executed and I can see "test" string appearing in the browser's console. However it looks like socket.emit() is not executed.

How do I know it is not executed? So When I uncoment line with next socket.emit() below (it will be executed during setValue() execution) I can see that it gets executed as on the server I see that onDeviceActivate() is executed so the "device_activate" event is received at the server side.

Could you tell me please what I could be doing wrong here? Why socket.emit() doesn't work on button press? I don't see any exception in the browser console.

You put socket.emit() inside a .click() handler. It won't get called until sometime later (if ever) when that object in the page actually gets clicked.

.click() handlers (as with nearly all event handlers) are non-blocking and asynchronous and they get called some indeterminate time in the future.

This code also has another potential problem if the client receives more than one device message, then each time you get one, you will add yet another .click() handler so that when that item is actually clicked, you may get multiple click handlers all firing on the same event. That is pretty much never what you want.

If you had explained in more detail in your question what overall problem you were actually trying to code, we could perhaps suggest a better way to structure your code that does not have this issue.


Your code is also using a number of undeclared variables. This is a big bad no-no in Javascript. In fact, if you run your code in strict mode (which you really should), then this will even be an error because it's evil. When you assign to an undeclared variable such as devArdID , it becomes an implicit global. That means that multiple calls to the same function can easily overwrite the variable the previous call was using. You should never do this.

Also declare every single variable you use with var , let or const and declare it in the closest scope you can (usually within the function or block where it is used).


Because you're using .use() on the server-side, that is middleware. You have to call next() after your processing to allow the connection to continue. If you don't call next() , then the connection doesn't really happen properly.

io = require('socket.io').listen(this.server);
io.of('/iot').use(onWSAuthorize);

function onWSAuthorize(socket, next) {
    socket.on('device_activate', function (msg) {
        console.log('device_activate received');
        onDeviceActivate(msg, socket)
    });
    // let middleware proceed
    next();
}

I'm not quite sure why you aren't doing this the more traditional way as there does not appear to be any reason for you to be using middleware:

io.of('/iot').on('connect', (socket) => {
    socket.on('device_activate', function (msg) {
        console.log('device_activate received');
        onDeviceActivate(msg, socket)
    });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM