0

The click event on the button is fired once when it is called the first time only and I don't know why that is happening, I'm using the latest version of socket.io, express and passport as of 11/2/2021 (dd/mm/yy).

I'm trying to build a real-time chatting web app when the user click on the button it should display his message in the message box and apply the function called myMsg(name, body), I don't have a problem with my emits I think, because the msg is sent to the other side successfully when the event is fired the first time only.

Client JS:

const msgbox = (name, body)=>{
  const element = `<div class="message-recieved">
  <p><strong>${name}</strong></h>
  <p>${body}</p></div>`;
  document.querySelector(".scroll").insertAdjacentHTML("beforeend", element);
}

const myMsg = (name, body) =>{
  const element= `<div class="msg-sent ml-auto">
  <p><strong>${name}</strong></p>
  <p>${body}</p></div>`;
  document.querySelector(".scroll").innerHTML += element;
}


$(".button").click(function(event){
  const userId = event.target.value;
  const msg = {
    userId: userId,
    body: document.querySelector(".message").value
  };
  if(msg.body !== null){
    const name = document.querySelector(".active").textContent;
    myMsg(name, msg.body);
    socket.emit("publicMessage", msg);
  }
  return false;
});

socket.on("publicMessage", function(msg, name){
  msgbox(name, msg.body);
});


App JS:

io.on('connection', function(socket) {
  console.log("Made socket connection");
  socket.on("publicMessage", function(msg) {
    User.findOne({
      _id: msg.userId
    }, function(err, found) {
      if (found) {
        found.messages.push(msg.body)
        socket.broadcast.emit("publicMessage", msg, found.fullName);
      }
    })
  });
});

My HTML:

<form class="">
      <div class="input mr-auto ml-auto">
          <div class="input-group">
            <input class="message" value="" type="text" class="form-control" placeholder="Message" aria-label="Message" aria-describedby="message">
            <div class="input-group-append">
              <button class="btn btn-outline-primary button" type="button" name="button" value="<%=userId%>" id="button-addon2">Send</button>
            </div>
          </div>
      </div>
    </form>

My App JS setup code:

const express = require("express");
const bodyParser = require("body-parser");
const socket = require('socket.io');
const app = express();
const activeUsers = new Set();
const Users = [];
const ejs = require('ejs');
const mongoose = require("mongoose");
const session = require('express-session')
const passport = require('passport');
const passportLocalMangoose = require("passport-local-mongoose");

app.use(session({secret: process.env.SECRET, resave: false, saveUninitialized: false}));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static("public"));
app.use(bodyParser.urlencoded({extended: true}));

mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
mongoose.set('useUnifiedTopology', true);

mongoose.connect("mongodb://localhost:27017/usersDB");

const userSchema = new mongoose.Schema({fullName: String, email: String, password: String, messages: [String]});

userSchema.plugin(passportLocalMangoose);

const User = new mongoose.model("User", userSchema);

passport.use(User.createStrategy());

passport.serializeUser(function(User, done) {
  done(null, User.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});

app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + "/public"));

const server = app.listen(3000, function(err) {
  if (!err) {
    console.log("Server is running on port 3000");
  } else {
    console.log(err);
  }
});

const io = socket(server);

  • Is the button inside the `.scroll` DIV? – Barmar Feb 11 '21 at 16:37
  • @Barmar yes, it is inside the `.scroll` div – Omar Ashraf Feb 11 '21 at 17:30
  • Then either use jquery `.append()` or JS `.insertAdjacentHTML()` instead of `.innerHTML +=` – Barmar Feb 11 '21 at 17:36
  • When you concatenate to `innerHTML`, the DOM of the element is reconstructed from the HTML, and all dynamic changes are lost, including event listeners. – Barmar Feb 11 '21 at 17:37
  • @Barmar same issue, tried both `insertAdjacentHTML()` and `append()`, when I fire the event for the first time, the element is added and on the second try, nothing is added. – Omar Ashraf Feb 11 '21 at 17:52
  • You can also use event delegation, see https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements – Barmar Feb 11 '21 at 17:55
  • Have you narrowed down whether the problem is with the click event handler or the socket code? Add `console.log()` calls so you see which functions are being called. – Barmar Feb 11 '21 at 17:57
  • @Barmar the last resource explains adding events to dynamically created elements which I'm not doing, my problem is that my button fires only once while it should fire every time I click on it plus I don't add any event to my dynamically created messages. – Omar Ashraf Feb 11 '21 at 18:02
  • When you recreate a DOM element from HTML, all the elements within it are created dynamically. – Barmar Feb 11 '21 at 18:04
  • @Barmar It's not about my socket code because on the other side I receive the message once the event is fired for the first time, but nothing happens when I want to send a new message, the only way for me to send a new message from the same user is to reload the page – Omar Ashraf Feb 11 '21 at 18:05
  • I'm grasping at straws, I can't think of any other reason why the event isn't firing on the second click. – Barmar Feb 11 '21 at 18:05
  • You use `insertAdjacentHTML` in `msgbox()` now, but you're still using `innerHTML +=` in `myMsg()` – Barmar Feb 11 '21 at 18:07
  • @Barmar Okay got you!! – Omar Ashraf Feb 11 '21 at 18:07
  • @Barmar Thanks man, I'll try what you said about DOM elements, my from is inside the scroll DIV, that's why this is happening – Omar Ashraf Feb 11 '21 at 18:08
  • @Barmar issue is solved!! Thanks man – Omar Ashraf Feb 11 '21 at 18:22

1 Answers1

0

Thanks for @Barmar, and other people who helped me in the comments.

This problem happened because whenever you create a child element inside a parent element, all the elements inside that parent are recreated and all event listeners inside that parent are not set.

please refer to the comments for more details.