socket.io, getting io is not defined on console - javascript

I am setting a basic chat app using sockets, but in the initial stage of programming I am getting this error: “io is not defined” on the client side.
I have tried including the CDN and adding
<script src="/socket.io/socket.io.js"></script>,
but no success.
HTML
<head>
<script src="jquery-3.2.1.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script src="script.js"></script>
</head>
script.js
let socket = io();
console.log("socket formed on " + socket.id)
server.js
const express = require('express')
const path = require('path')
const socketio = require('socket.io')
const http = require('http')
const app = express();
const server = http.createServer(app)
const io = socketio(server)
app.use('/', express.static(path.join(__dirname, 'frontend')))
io.on('connection', (socket) => {
console.log("New socket formed fksrom " + socket.id)
})
server.listen(2345, () => console.log('website open on http://localhost:2345'))
I expect the socket ID to be shown in the console,
but on console it is displaying “io is not defined”.

I think you should check if document has loaded so here's the code below:
// Pure Javascript
if(document.readyState === "complete") {
//Already loaded!
}
else {
//Add onload or DOMContentLoaded event listeners here: for example,
window.addEventListener("onload", function () {/* Move your code here */}, false);
//or
//document.addEventListener("DOMContentLoaded", function () {/* code */}, false);
}
Since you already have jQuery:
$(document).ready(function(){
/** Your code here */
})
You're trying to access a script before it is loaded so the above code should help you run your script only when you've done with loading the jQuery library and socket.io.js library.

Related

Electron: Linking pages using buttons click event

I have created a button(Connect), when I click it should go to the other page(second.html). It works with localhost, but not with Electron App. What am I doing wrong?
<script>
$(document).ready(() => {
$( '#buttonConnect').on('click',() =>{
const inputIp = $('#ip');
if(inputIp.val() !== ""){
window.location.href = "observer.html ?ip="+inputIp.val();
}else{
alert("Check Connection Settings!");
}
});
});
</script>
<button class="btn btn-primary" id="buttonConnect">Connect</button>
You need to communicate with electron from your remote window to tell it which URL to load.
Using IPC is the recommended way of doing that.
(a former solution was using remote which is deprecated now)
In your remote code (your jQuery code from above, in this case):
let { ipcRenderer } = require("electron");
$(document).ready(() => {
$( '#buttonConnect').on('click',() =>{
const inputIp = $('#ip');
if (inputIp.val() !== ""){
ipcRenderer.send("load-page", `second.html?ip=${inputIp.val()}`);
}
else {
alert("Check Connection Settings!");
}
});
});
In your main electron code (probably app.js):
let electron = require("electron");
let { BrowserWindow, ipcMain } = electron;
// ...
ipcMain.on("load-page", (event, uri) => {
let win = new BrowserWindow({ /* ... */ });
// I don't know your directory structure.
// You may have to adapt the following line.
win.loadURL(`file://${__dirname}/${uri}`);
});

How do I trigger javascript from a button click

I'm trying to trigger javascript to start, stop and restart a stopwatch from a button in the html file. What is the best way to pass an event from the html to the javascript?
I have managed to trigger a console log when the button is pressed, but I can't put in the javascript in the second js file. I just receive errors. Would socket.io work? I have investigated Event emitters and listeners but I think it's out of my skill level.
server.js
var express = require('express');
var app = express();
var path = require('path');
var Stopwatch = require("node-stopwatch").Stopwatch;
const EventEmitter = require('events');
var stopwatch = Stopwatch.create();
app.use(express.static('public'));
// start the express web server listening on 8080
app.listen(8080, () => {
console.log('listening on 8080');
});
// serve the homepage
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
stopwatch.start();
/*
stopwatch output test
*/
console.log("ticks: " + stopwatch.elapsedTicks);
console.log("milliseconds: " + stopwatch.elapsedMilliseconds);
console.log("seconds: " + stopwatch.elapsed.seconds);
console.log("minutes: " + stopwatch.elapsed.minutes);
console.log("hours: " + stopwatch.elapsed.hours);
//stop it now
stopwatch.stop();
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
client.js
console.log('Client-side code running');
const button = document.getElementById('myButton');
button.addEventListener('click', function(e) {
console.log('button was clicked');
});
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Stopwatch</title>
</head>
<body>
<h1>Stopwatch</h1>
<p id="counter">Loading button click data.</p>
<button id="myButton">Click me!</button>
</body>
<script src="client.js"></script>
</html>
I expected to trigger the javascript on button click but I cannot run it in client.js
Use in the client.js
window.addEventListener("load", myFunction);
and place your code to myFunction
If this console is printed, console.log('Client-side code running');
Try to add your button event inside a function.
function onLoadBody() {
const button = document.getElementById('myButton');
button.addEventListener('click', function(e) {
console.log('button was clicked');
});
}
<body onload="onLoadBody()" >...
let say you have two files, client.js and server.js
You can use socket.io for quicker response as apposed to HTTP request
You just need to emit a key to the server and the server will respond to that emit.
Client.js
let socket = io();
socket.emit('start')
Server.js
socket.on('start',(data)=>{
// do what ever you want and send back to client with the same emit method
// `socket.emit()` sends message to connected client
// socket.broadcast.emit() send message to all clients except you
// io.emit() send message to all including you
})

How do I use eventListeners with Angularjs + Electron?

I am learning Electron and built my own "hello world" type application that works. I started learning it like an hour ago so any noob friendly tips are highly appreciated.
I decided to include angularjs + angular material to style it and see how it works. Now my piece of code that sends notification isn't working. That raised a question.
How do I send click events from angularjs to electron?
Here is the sample code from all files
main.js copied from get-started electron github page
const electron = require('electron');
const {ipcMain} = require('electron');
// Module to control application life.
const {app} = electron;
// Module to create native browser window.
const {BrowserWindow} = electron;
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
function openInbox() {
win.loadURL('https://inbox.google.com/?pli=1');
}
function createWindow() {
// Create the browser window.
win = new BrowserWindow({width: 1366, height: 768});
// and load the index.html of the app.
win.loadURL(`file://${__dirname}/index.html`);
win.openDevTools();
// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null;
});
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
ctrl.js // renderer file that used to work and send notifications prior to including angularjs + material lib
const {ipcRenderer} = require('electron');
const button = document.getElementById('button');
button.addEventListener('click', evt => {
new Notification('Angular Material FTW!');
});
index.html
<!DOCTYPE html>
<html ng-app="webApp">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-aria.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.7/angular-material.min.js"></script>
<script src="angular-main.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.7/angular-material.min.css">
</head>
<body layout-align="center center" layout-padding>
<h1 id="hello">Hello World!</h1>
<div></div>
<md-button class="button md-raised md-primary">Click Me</md-button>
</body>
<script src="ctrl.js"></script>
</html>
angular-main.js Angular file
(function() {
angular
.module('webApp', ['ngMaterial'])
.config(themeConfiguration)
.controller('appCtrl', appCtrl);
function themeConfiguration($mdThemingProvider) {
$mdThemingProvider.theme('default')
.primaryPalette('blue', {
'default': '500'
})
.accentPalette('red')
.warnPalette('deep-orange')
.backgroundPalette('grey', {
'default': '100'
});
}
function appCtrl() {
var vm = this;
vm.notification = function Notification(evt) {
new Notification('Hello angular');
};
}
})();
If I remove Angularjs and Material the ctrl.js works and send notification just fine.
Answering my own question, to make things work just place code inside angularjs Controller function like this
function appCtrl() {
var vm = this;
const button = document.getElementById('button');
button.addEventListener('click', evt => {
new Notification('Angular Material FTW!');
});
}

WebSocket callback to answer to message

I am playing with a simple exercise with WebSockets. I have a NodeJS script that listens on a WebSocket, receives a file name, opens the file, and sends the content of the file back to the client through the WebSocket.
Here is the code:
var websocket_server = require('ws').Server;
var server = new websocket_server({port: 1234});
var fs = require('fs');
server.on('connection', function connection(socket)
{
  socket.on('message', function request(file_name)
  {
    fs.readFile(file_name, function(error, data)
    {
      if(error)
        throw error;
      socket.send(data, {binary: true});
    });
  });
});
On the client side, I use a WebSocket to load an image and display it in the page:
<!DOCTYPE html>
<html>
<head>
<title>My Little Project</title>
<script type = "text/javascript">
var ws = new WebSocket("ws://127.0.0.1:1234");
ws.binarytype = "blob";
ws.onmessage = function(event)
{
var img = document.createElement("img");
img.src = (window.URL || window.webkitURL).createObjectURL(event.data);
document.body.appendChild(img);
}
ws.onopen = function(event)
{
ws.send("image1.jpg")
}
</script>
</head>
<body>
</body>
</html>
Now, this example works fine, and I am happy. What makes me sad is that I would now like to ask the server for multiple images, and to do something with each.
I know that I could serialize all my requests by doing something like:
ws.onmessage = function(event)
{
// Do something with image1.jpg
ws.onmessage = function(event)
{
// Do something with image2.jpg
// And so on
}
ws.send("image2.jpg");
};
ws.send("image1.jpg");
But this is serial, which adds overhead and so on. What I would like to get is something like:
ws.send("image1.jpg", function(event)
{
// Do something with image1.jpg
});
ws.send("image2.jpg", function(event)
{
// Do something with image2.jpg
});
// And so on
I have no clue on how to do this neither on the client nor on the server, so any help would be greatly appreciated.
You should use the library websockets-callback which does exactly what you want.
Here is part of the code that is included in the demo:
function onTestProgressClick(){
var milliseconds = document.getElementById("callbackDelay").value;
//magic starts here
wsc.send({cmd: 'progress'},
function(response){
document.getElementById("ws_response").innerHTML = 'Progress test completed!';
},
function(response){
document.getElementById("progressBar").value = response.progress;
}
)
}
Why don't you just send images as json-encoded array and then handle it on server-side? I've not run this code, but it should work.
let images = [
"image1.jpg",
"image2.jpg",
];
ws.send(JSON.stringify(images), function(event)
{
// Do something with images
});

Nodejs, express & socket.io communicate between two static client pages

i am trying to build a remote for a gallery by using nodejs, express & socket.io.
the structure is as follows
/index.js
/public/screen.html
/screen.js
/remote.html
/remote.js
the idea is to have a gallery of images displayed on remote.html, select one and send the selected index to screen.html by using socket.io.
as of now my code looks like this:
index.js
var express = require('express');
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io').listen(server);
app.use(express.static('public'));
server.listen(8080, function(){
// setup image gallery and stuff...
connectToServer();
});
remote.js
var socket = null;
document.addEventListener("DOMContentLoaded", function(event) {
//some stuff
connectToServer();
});
function showImage (index){ //called by events
console.log('selected incdex: ' + index);
if(socket != null) {
socket.emit('selection', {id: index});
};
}
function connectToServer(){
socket = io.connect('http://localhost:8080');
socket.on('connection', function (socket) {
var text = document.querySelector('#name');
socket.emit('newRemote', 'new remote connected');
console.log('emitted welcome');
socket.on('newScreen', function (data) {
console.log(data);
});
});
}
screen.js
var socket = null;
document.addEventListener("DOMContentLoaded", function(event) {
//some stuff
connectToServer();
});
function connectToServer(){
socket = io.connect('http://localhost:8080');
socket.on('connection', function (socket) {
var text = document.querySelector('#name');
socket.emit('newScreen', { name: name });
socket.on('newRemote', function (data) {
console.log(data);
});
});
};
when starting with node index.js i get
listening on *:8080
and when loading screen or remote.html i get
debug - client authorized
info - handshake authorized MwtGFRCZamcyKkUpK5_W
as I see it: somehow a connection is established, but:
no messages are sent / received on both ends
no logs are printed to the console for the connection events
any idea why nothing is happening?
It appears that you have mixed server-side code into your client. The 'connection' event is an event that needs to be listened to on the server, not your client files. Additionally, you cannot directly call client-side functions from your server-side code.
The below code does not work:
server.listen(8080, function(){
// setup image gallery and stuff...
connectToServer();
});
To achieve the above you will need to put the following code on your server:
server.listen(8080, function(){
socket.on('connection', function (socket) {
// setup image gallery and stuff...
socket.emit('connectToServer', myPassedParameters);
});
});
And the following listener for that event on the client:
socket.on('connectToServer', function (myPassedParameters) {
var text = document.querySelector('#name');
// stuff for client side here
});
});
In addition to the above, you cannot do calls from one client file to another client file using socket.io. You would have to do a call to the server first and then call a function on the other file once it has been loaded for the user.

Categories