NodeJS Angular 8 chat application not receiving messages in client - node.js

I made a NodeJS server and an Angular 8 client to send and receive messages with socket.io. The server does receive the message but does not send/angular does not receive the message. Does this happen because I use localhost or did I do something wrong codewise?
NodeJS server:
let express = require('express');
let app = express();
let http = require('http');
let server = http.Server(app);
let socketIO = require('socket.io');
let io = socketIO(server);
const port = process.env.PORT || 3000;
io.on('connection', (socket) => {
console.log('user connected');
socket.on('new-message', (message) => {
console.log(message);
io.emit(message);
});
});
server.listen(port, () => {
console.log(`started on port: ${port}`);
});
Angular service:
import * as io from 'socket.io-client';
import { Observable } from 'rxjs/Observable';
import {Observer} from 'rxjs';
export class ChatService {
private url = 'http://localhost:3000';
private socket;
constructor() {
this.socket = io(this.url);
}
public sendMessage(message) {
this.socket.emit('new-message', message);
}
public getMessages = () => {
// return Observable.create((observer) => {
// console.log(observer);
// this.socket.on('new-message', (message) => {
// observer.next(message);
// });
// });
return new Observable((observer) => {
this.socket.on('new-message', (message) => {
observer.next(message);
observer.complete();
});
});
}
}
Angular component:
export class HomeComponent implements OnInit {
private message: string;
constructor(private chatService: ChatService) {
this.message = 'hello';
this.sendMessage();
}
ngOnInit(): void {
this.chatService.getMessages().subscribe((message: string) => {
console.log(message);
}, err => {
console.log(err);
});
}
sendMessage() {
this.chatService.sendMessage(this.message);
}
}
App.module.ts:
#NgModule({
declarations: [
AppComponent,
HomeComponent
], imports: [
], providers: [
ChatService
], entryComponents: []
})
export class AppModule {
}

In your server code you wrote io.emit(message); but emit function is called with two parameters - event name, and message to send.
Change it into io.emit('new-message', message); and it should work.

you need to change io.emit(message) to io.emit("message", { message: message }).
this code worked for me.

Related

io.on returns undefined, using socket.io, node and angular

I have a problem using socket.io, when I do an io.on it doesn't pass the parameter. When the parameter arrives at the client, it comes undefined.
in node, when I send io.to(${room}).emit("number", JSON.parse('{"number":"1"}'))
the value passed is undefined, even passing a set value
server node:
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const cors = require('cors');
const io = require('socket.io')(server, {
cors: {
origin: '*',
}
});
users = []
app.get('/', (req, res) => {
res.send('<h1>Hello world</h1>');
});
server.listen(3000, () => {
console.log('listening on *:3000');
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('conexao', (data)=>{
console.log(data)
})
socket.on('joinRoom', data=>{
console.log(data)
const userInRoom = users.find(user=> user.username === data.name && user.room === data.room)
if(userInRoom){
userInRoom.socketId = socket.id
}else{
users.push({
socketId: socket.id,
username: data.name,
room: data.room
})
}
socket.join(data.room)
console.log("sala criada")
})
socket.on("room", (room)=>{
io.to(`${room}`).emit("number", JSON.parse('{"number":"1"}'))
})
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
io.attach(server)
});
```
here I am passing a number informing what the room is and I want to receive a parameter to test if the room is working. to get to this page the user has already entered the room angular typescript that makes the call:
```
import { SocketService } from './../../services/socket.service';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-room',
templateUrl: './room.component.html',
styleUrls: ['./room.component.scss']
})
export class RoomComponent implements OnInit {
roomNumber:string = ''
constructor(private socket:SocketService){
}
ngOnInit(): void {
this.socket.on('number', (numero:JSON) =>{
console.log(numero)
const obj = JSON.parse(numero.toString())
console.log("test")
this.roomNumber = obj.number
})
}
emit(){
this.socket.emit('room', 123456 )
}
}
```
appmodule:
```
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { SocketIoModule, SocketIoConfig } from 'ngx-socket-io';
import { HeaderComponent } from './templates/header/header.component';
import { FooterComponent } from './templates/footer/footer.component';
import { HomeComponent } from './components/home/home.component';
import { RulesComponent } from './components/rules/rules.component';
import { RoomComponent } from './components/room/room.component';
const config: SocketIoConfig = {url:'http://localhost:3000'}
#NgModule({
declarations: [
AppComponent,
HeaderComponent,
FooterComponent,
HomeComponent,
RulesComponent,
RoomComponent
],
imports: [
BrowserModule,
AppRoutingModule,
SocketIoModule.forRoot(config)
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
```
The code is simple because I'm just testing the communication to continue the project.
erro: ERROR TypeError: Cannot read properties of undefined (reading 'toString')
at room.component.ts:18:37
at SocketService.on (socket.service.ts:16:31)
at RoomComponent.ngOnInit (room.component.ts:16:17)
at callHook (core.mjs:2488:22)
at callHooks (core.mjs:2457:17)
at executeInitAndCheckHooks (core.mjs:2408:9)
at refreshView (core.mjs:10434:21)
at refreshEmbeddedViews (core.mjs:11434:17)
at refreshView (core.mjs:10443:9)
at refreshComponent (core.mjs:11480:13)
I'm sending a call to the socket passing the room number and it should pass me a number back. instead it passes undefined. I've tried passing number, string and JSON and nothing worked. detail that the room is being created, as the error only happens if I am in the room "123456"

Nest.js equivalent program for below Node snippet

Can someone please help and tell me how I can write the following code snippet which is written as a node application to write as a nest application with just WebSockets and gateway class?
var webSocketsServerPort = 8080;
var webSocketServer = require('websocket').server;
var http = require('http');
var server = http.createServer(function(request, response) {
});
server.listen(webSocketsServerPort, function() {
console.log(
new Date() + ' Server is listening on port ' + webSocketsServerPort
);
);
});
var wsServer = new webSocketServer({
httpServer: server
});
wsServer.on('request', function(request) {
var connection = request.accept(null, request.origin);
connection.on('message', function(data) {
var message = JSON.parse(data.utf8Data);
});
connection.on('close', function(connection) {});
EDIT:
In main.ts I wrote this :
app.useWebSocketAdapter(new WsAdapter(app));
This is how my gateway class looks like:
import { WebSocketGateway, WebSocketServer, OnGatewayInit, OnGatewayDisconnect, OnGatewayConnection, SubscribeMessage } from "#nestjs/websockets";
import { Server } from "websocket";
import { Logger } from "#nestjs/common";
#WebSocketGateway(8080)
export class ChatterGateway implements OnGatewayInit, OnGatewayDisconnect, OnGatewayConnection {
#WebSocketServer() private server: server;
private logger: Logger = new Logger('ChatterGateway');
afterInit(server: server) {
this.logger.log('ChatGetway init');
}
handleConnection(client: any, data) {
this.logger.log('Client connected');
}
handleDisconnect(client: any) {
this.logger.log('Client disconnected');
}
#SubscribeMessage('request')
handleRequest(client: any, data) {
this.logger.log(data);
}
#SubscribeMessage('message')
handleMessage(client: any, data) {
this.logger.log(data);
}
}

Angular HTTP GET not hitting Express Route

My Angular HTTP GET Request indside clearNotifications() in notification.service.ts not hitting Express Route routes/notifications.js. I am calling clearNotifications() from a component called app.component.ts. I am using Angular 7+
routes/notifications.js
const router = require('express').Router();
//Additional modules
// const db = require('../config/database');
// const notificationModel = require('../models/notifications');
//Test connection
// db.authenticate().then(() => {
// console.log('Connection has been established successfully.');
// }).catch(err => {
// console.error('Unable to connect to the database:', err);
// });
//Clear all notifications
router.get('/clear', (req, res, next) => {
console.log('clear');
// notificationModel.destroy({});
});
module.exports = router;
notification.service.ts
import { Injectable } from '#angular/core';
import * as io from 'socket.io-client';
import { Observable } from 'rxjs';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class NotificationService {
uri = 'http://localhost:5000';
private socket = io(this.uri);
constructor(private http: HttpClient) { }
getNotification() {
let observable = new Observable<{ string: String, number: String }>(observer => {
this.socket.on('notification', (data) => {
observer.next(data);
});
// return () => { this.socket.disconnect(); }
})
return observable;
}
clearNotifications() {
return this.http.get(`${this.uri}/notifications/clear`);
}
}
app.component.ts
import { Component } from '#angular/core';
import { NotificationService } from './notification.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [NotificationService]
})
export class AppComponent {
title = 'client';
string: String;
number: String;
notificationArray: Array<{ string: String, number: String }> = [];
constructor(private notificationService: NotificationService) {
this.notificationService.getNotification().subscribe(data => {
this.notificationArray.push(data);
});
}
clearNotifications() {
this.notificationArray = [];
this.notificationService.clearNotifications();
}
}
You should be doing this: Check the basic routing on express
var express = require('express');
var app = express();
app.get('/clear', (req, res) => {
console.log('clear');
res.send(success);
// notificationModel.destroy({});
});
Also make sure to subscribe to the service method from your component. If you do not subscribe the observables won't execute.
Where are you calling clearNotifications from?
subscribe to clearNotifications in component and this will work:
this.notificationService.clearNotifications().subscribe( (data) => { ..})
As a publisher, you create an Observable instance that defines a subscriber function. This is the function that is executed when a consumer calls the subscribe() method. The subscriber function defines how to obtain or generate values or messages to be published
In angular, http request returns observable, so you need to subscribe. If there aren't any subscriber to the observable, it wont be executed. Try
clearNotifications() {
return this.http.get(`${this.uri}/notifications/clear`)
.subscribe(data => //your callback function,
error => // your error handler,
complete => // any after completion task);
}

How to receive data from client using socket.io events inside express controller?

I am using Express framework with TypeScript:
I want to get client location at login using Socket IO, so on the client side, i made an emit event on login page. On the server side i tried to integrate a socket event into the login controller, which is placed before the response is sent back to the client, but the event from the server fires up just after i'm already signed in and clicked on sign out button which leads me to login page again (this is the moment when i receive the location message on server side from console.log(data)).
This is how the authentication controller file (auth.controller.ts) looks like:
import { io } from '../server/https';
....
..
public authenticate(req: Request, res: Response) {
if(req.body.email && req.body.password) {
....
..
io.on('connection', (socket: SocketIO.Socket) => {
console.log('New Socket Connected!');
socket.on('client-location', (data) => {
console.log(data);
});
socket.on('disconnect', (reason) => {
console.log(reason);
});
});
res.status(200).json({
resType: 'success',
token: 'Bearer ' + token,
userId: user.id,
message: 'Authenticated.',
loginNumber: result.session.length
});
};
....
..
}
The { io } import in the auth.controller.ts is the exported io constant from https.ts file.
Below is the https.ts file:
import socketIO from 'socket.io';
import HTTPS from 'https';
import app from '../app/index';
....
..
const options = {
cert: fs.readFileSync(path.resolve('../../../certificates/ca.crt')),
key: fs.readFileSync(path.resolve('../../../certificates/ca.key'))
}
export const server = HTTPS.createServer(options, app)
.listen(process.env.HTTP_SERVER_PORT, () => {
console.log(`Platform Server is running from
${process.env.HTTP_SERVER_HOST}, port: ${process.env.HTTP_SERVER_PORT}`);
});
export const io = socketIO.listen(server);
Something is not synchronized and i don't get it.
The client side is wrote in Angular 6 and the component from where the event is emited is below:
import { Component, OnInit } from '#angular/core';
import { LoginService } from '../../services/login.service';
import { Router } from '#angular/router';
import * as io from 'socket.io-client';
import { env } from '../../../../../environments/environment';
#Component({
selector: 'login-form',
templateUrl: './login-form.component.html',
styleUrls: ['./login-form.component.css']
})
export class LoginFormComponent implements OnInit {
public positionOptions = {
enableHighAccuracy: true,
maximumAge: 0
};
public LoginFormModel: any = {};
private URL = `${env.WS_SERVER_URL}:${env.HTTP_SERVER_PORT}`;
private socket;
constructor(private loginController: LoginService,
private router: Router) {
this.socket = io(this.URL);
}
ngOnInit() {}
public emitLocation() {
navigator.geolocation.getCurrentPosition(position => {
const { latitude: lat, longitude: lng } = position.coords;
console.log({ lat, lng });
this.socket.emit('client-location', { lat, lng });
},
err => {
console.log(err);
}, this.positionOptions);
}
loginEvent() {
this.loginController.login(this.LoginFormModel.email.value,
this.LoginFormModel.password.value)
.subscribe(
result => {
this.loginController.createSession('token', result.token);
this.emitLocation();
this.router.navigate(['user/profile']);
},
err => {
console.log(err);
});
}
}

Angular2 CLI Socket.io Cannot read property 'on' undefined

I want to use socket.io module for sending message and I am newbie in using it. I am trying to run socket.io within my Angular2 CLI + Node.js application and I am getting following error:
TypeError: Cannot read property 'on' of undefined
at MessagesComponent.webpackJsonp.363.MessagesComponent.sendMessage
(messages.component.ts:34)
What is wrong with my code and how can I connect and send message to the socket.io server?
messages.component.html
<div class="stick" style="background-color:#F5F5F5;">
<h5>Messages:</h5>
<ul>
<li *ngFor="let msg of msgs">
{{msg}}
</li>
</ul>
<input #mm/>
<button (click)="sendMessage(mm.value); mm.value=''">Send</button>
</div>
messages.component.ts
import { Component,Input,OnInit,Output,EventEmitter,HostListener,ElementRef, NgZone} from "#angular/core";
import * as sio from 'socket.io-client';
import { Observable } from 'rxjs/Observable';
#Component({
selector: "messages",
templateUrl: './messages.component.html'
})
export class MessagesComponent implements OnInit{
socket: SocketIOClient.Socket;
private url = 'http://localhost:4200';
constructor(private _zone: NgZone, public http: Http) {}
ngOnInit() {
}
sendMessage(message){
this.socket.on('connect', function(data) {
this.socket.emit('add-message', message);
});
}
getMessages() {
let observable = new Observable(observer => {
this.socket = io(this.url);
this.socket.on('message', (data) => {
observer.next(data);
});
return () => {
this.socket.disconnect();
};
})
return observable;
}
}
www.ts
import { app } from '../app';
import * as http from 'http';
/**
* Get port from environment and store in Express.
*/
const port = normalizePort(process.env.PORT || 3000);
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
let io = require('socket.io').listen(server);
io.on('connection', (socket) => {
socket.on('disconnect', function(){
console.log('user disconnected');
});
socket.on('add-message', (message) => {
io.emit('message', {type:'new-message', text: message});
});
});
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
Solution:
constructor(private _zone: NgZone, public http: Http) {
this.socket = sio(this.url);
}
in your on callback use arrow function to preserve this keyword :
sendMessage(message){
this.socket.on('connect', (data) => {
this.socket.emit('add-message', message);
});
}
you have to instantiate your socket :
constructor(private _zone: NgZone, public http: Http) {
this.socket = sio(this.url);
}
in your on callback use arrow function to preserve this keyword :
sendMessage(message){
this.socket.on('connect', (data) => {
this.socket.emit('add-message', message);
});
}

Resources