Reputation: 43
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
Reputation: 708036
Based on your console screen grab, there are at least two problems here:
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.
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
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