Peplm
Peplm

Reputation: 43

Javascript code not running on PUG/Jade file

I'm following this tutorial to implement a tic tac toe game using socket.io: https://ayushgp.github.io/Tic-Tac-Toe-Socket-IO/ .

But I also want to use a login system.

When the user logs in, it successfully goes to this page (I converted html to pug), located on /views/game.pug

doctype html
html
  head
    title Tic Tac Toe
    link(rel='stylesheet', href='/css/main.css')
    link(rel='stylesheet', href='/node_modules/skeleton-css/css/skeleton.css')
  body
    .container
      .menu
        h1 Tic - Tac - Toe
        h3 How To Play
        ol
          li Player 1 Create a new game by entering the username
          li
            | Player 2 Enter another username and the room id that is displayed on first window.
          li Click on join game. 
        h4 Create a new Game
        input#nameNew(type='text', name='name', placeholder='Enter your name', required='')
        button#new New Game
        br
        br
        h4 Join an existing game
        input#nameJoin(type='text', name='name', placeholder='Enter your name', required='')
        input#room(type='text', name='room', placeholder='Enter Game ID', required='')
        button#join Join Game
      .gameBoard
        h2#userHello
        h3#turn
        table.center
          tr
            td
              button#button_00.tile
            td
              button#button_01.tile
            td
              button#button_02.tile
          tr
            td
              button#button_10.tile
            td
              button#button_11.tile
            td
              button#button_12.tile
          tr
            td
              button#button_20.tile
            td
              button#button_21.tile
            td
              button#button_22.tile
    .container
    script(src='/node_modules/jquery/dist/jquery.min.js')
    script(src='/socket.io/socket.io.js')
    script(src='/js/main2.js')

That works fine. But when I click the button with id #new, nothing happens. This is the error I get: https://i.sstatic.net/NwrVc.png .

This is the relevant part of main2.js, located on /public/js/main2.js:

  $('#new').on('click', () => {
    const name = $('#nameNew').val();
    if (!name) {
      alert('Please enter your name.');
      return;
    }
    socket.emit('createGame', { name });
    player = new Player(name, P1);
  });

EDIT:

Files' locations:

main.css on /public/css/main.css

skeleton.css on /node_modules/skeleton-css/css/skeleton.css

jquery.min.js on /node_modules/jquery/dist/jquery.min.js

socket.io.js on /node_modules/socket.io-client/dist/socket.io.js

main2.js on /public/js/main2.js

app.js (only relevant parts are shown):

const express = require('express');
const path = require('path');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
app.use(express.static('.'));
//Load View engine
app.engine('pug', require('pug').__express);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

//Set public folder
app.use(express.static(path.join(__dirname, 'public')));

//This get request is sent after the user logs in. It works fine
    app.get('/users/game', function(req, res) {
        res.render('game', {
          title:'Game'
      });
    });

io.on('connection', (socket) => {
//See full code here:https://github.com/ayushgp/tic-tac-toe-socket-io/blob/master/index.js
}

let articles = require('./routes/articles');
let users = require('./routes/users');
app.use('/articles', articles);
app.use('/users', users);

Also, my main2.js file is identical to this one: https://github.com/ayushgp/tic-tac-toe-socket-io/blob/master/main.js

EDIT2: Full app.js code (the relevant part is the get request to users/game:

const express = require('express');
const path = require('path');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const expressValidator = require('express-validator');
const flash = require('connect-flash');
const session = require('express-session');
const config = require('./config/database');
const passport = require('passport');

let rooms = 0;

app.use(express.static('.'));

mongoose.connect(config.database, {
  useMongoClient: true
});
let db = mongoose.connection;

//Check connection
db.once('open', function(){
  console.log('Connected to MONGOdb')
});

//Check for DB errors
db.on('error', function(err){
  console.log(err);
});

//Bring in models
let Article = require('./models/article');

//Load View Engine
app.engine('pug', require('pug').__express);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

// Boddy parser middlware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

//Set public folder
app.use(express.static(path.join(__dirname, 'public')));

//Express Session Middleware
app.set('trust proxy', 1) // trust first proxy
app.use(session({
  secret: 'keyboard cat',
  resave: true,
  saveUninitialized: true,
  cookie: { secure: false }
}));

//Express Messages Middleware
app.use(require('connect-flash')());
app.use(function (req, res, next) {
  res.locals.messages = require('express-messages')(req, res);
  next();
});

//Express Messages Middleware
app.use(expressValidator());

//Passport Config
require('./config/passport')(passport);
//Passport Middleware
app.use(passport.initialize());
app.use(passport.session());

app.get('*', function(req, res, next){
  res.locals.user = req.user || null;
  next();
});


//Home ROute
app.get('/', function(req, res) {
  Article.find({}, function(err, articles){
    if(err){
      console.log(err);
    } else {
      res.render('index', {
        title:'Articles',
        articles: articles
      });
    }
  });
});

app.get('/users/game', function(req, res) {
    res.render('game', {
      title:'Game'
  });
});

io.on('connection', (socket) => {

    // Create a new game room and notify the creator of game.
    socket.on('createGame', (data) => {
        socket.join(`room-${++rooms}`);
        socket.emit('newGame', { name: data.name, room: `room-${rooms}` });
    });

    // Connect the Player 2 to the room he requested. Show error if room full.
    socket.on('joinGame', function (data) {
        var room = io.nsps['/'].adapter.rooms[data.room];
        if (room && room.length === 1) {
            socket.join(data.room);
            socket.broadcast.to(data.room).emit('player1', {});
            socket.emit('player2', { name: data.name, room: data.room })
        } else {
            socket.emit('err', { message: 'Sorry, The room is full!' });
        }
    });

    /**
       * Handle the turn played by either player and notify the other.
       */
    socket.on('playTurn', (data) => {
        socket.broadcast.to(data.room).emit('turnPlayed', {
            tile: data.tile,
            room: data.room
        });
    });

    /**
       * Notify the players about the victor.
       */
    socket.on('gameEnded', (data) => {
        socket.broadcast.to(data.room).emit('gameEnd', data);
    });
});

//Route files
let articles = require('./routes/articles');
let users = require('./routes/users');
app.use('/articles', articles);
app.use('/users', users);


//Start Sever
app.listen(3000, function() {
  console.log('Server running');
});

Upvotes: 1

Views: 6141

Answers (2)

jfriend00
jfriend00

Reputation: 708036

Based on your console screen grab, there are at least two problems here:

  1. Your server-side route (if you even have one) for script(src='node_modules/jquery/dist/jquery.min.js') is not working so jQuery never loads in the web page. Thus, no attempt to use jQuery works.

  2. Your socket.io server is not started or initialized properly on the server.

To be able to suggest fixes, we'd need to see the relevant server-side code and we'd need to know where all resources referenced in game.pug are located in your server-side file system (full path). You are either missing route a definition for the jQuery file or there's an error in the route definition.

It does look like main2.js is loading properly, though it immediately encounters an error because of the missing jQuery.


FYI, using script paths like this:

script(src='/node_modules/jquery/dist/jquery.min.js')

is generally not considered a good practice because it exposes and ties you to a specific server-side file structure. In general, you would do something like this instead:

app.use("/jquery", express.static(path.join(__dirname, "/node_modules/jQuery/dist")));

And, then use this in the client:

script(src='/jquery/jquery.min.js')

Now, the ONLY directory you've exposed to the public is /node_modules/jQuery/dist and you've not created a hard link between client web pages and server-side file structure.

You would repeat that process for each dist directory that you need to draw from. The way you have it now, you have granted public access to your entire node_modules server-side directory which is NOT something you want to do.


Also, when your socket.io server is working appropriately on the server, then it has a built-in route for socket.io.js. You can just use this in the client:

script(src='/socket.io/socket.io.js')

And, the socket.io server will automatically server the socket.io.js from that route. You don't have to manually create a route for that.


To get socket.io working properly, change this;

//Start Sever
app.listen(3000, function() {
  console.log('Server running');
});

to this:

//Start Sever
server.listen(3000, function() {
  console.log('Server running');
});

In these two lines of code, you created a web server and bound socket.io to it:

const server = require('http').Server(app);
const io = require('socket.io')(server);

But, then with app.listen(), you created a different web server and started it and never started the one that socket.io is connected to. Instead, you want to use server.listen(...) to start the one that you attached socket.io to.

Upvotes: 1

Songgen
Songgen

Reputation: 57

The code block will not working:

script(src='node_modules/jquery/dist/jquery.min.js')

please try like this:

app.use('/scripts', 
    express.static(path.join(__dirname, 'node_modules/jquery/dist')),
    // add some others
    );

app.use('/styles', 
    express.static(path.join(__dirname, '/node_modules/skeleton-css/css')),
    // add some others
    );

On view:

script(src='/scripts/jquery.min.js')
link(type='text/stylesheet' href='/styles/skeleton.css')

And you don't need the socket-io-client module for socket client.

On your code block, if you want the socket connection of the same original host, you don't need the socket-io-client module.

if you have created the socket server using socket.io, you can include the socket.io script like this when using view template.

script(type='text/javascript', src='/socket.io/socket.io.js')

Upvotes: 2

Related Questions