Ethan Chua
Ethan Chua

Reputation: 21

Socketio on Angular+NestJS Failing Silently

I am working on a beginner angular project and needed bidirectional communication between front- and backend and so I decided to use socket.io. I installed @nestjs/[email protected] (socket.io 4.8.1) for my backend (nest.js) and [email protected] for my frontend (Angular). My code is as follows:

Frontend:

curent-song.component.ts

import { Component, Input, OnInit, OnDestroy, inject} from '@angular/core';
import { SongEntry } from '../song-entry';
import { NgIf } from '@angular/common';
import { WebsocketService } from './websocket.service';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-current-song',
  standalone: true,
  imports: [NgIf, FormsModule],
  providers: [WebsocketService],
  templateUrl: './current-song.component.html',
  styleUrls: ['./current-song.component.css']
})
export class CurrentSongComponent implements OnInit, OnDestroy {
  @Input() song: SongEntry | null = null;
  isPlaying = false;
  currentTime = 0;
  duration = 100; // Initialize duration to 0
  volume = 50;
  socket: WebsocketService = inject(WebsocketService);
  constructor() {
    
  }
  ngOnInit() {
    this.socket.fromEvent('connected').subscribe(() => {
      console.log('Connected to server');
    });
    this.socket.fromEvent('connect_error').subscribe((err) => {
      console.log('Error connecting to server: ', err);
    });
  }
  ngOnDestroy(): void {
    this.socket.disconnect();
  }
}

websocket.service.ts

// src/app/services/socket.service.ts
import { Injectable } from '@angular/core';
import { Socket } from "ngx-socket-io";
import { Observable } from 'rxjs';

@Injectable()
export class WebsocketService {
  constructor(private socket:Socket) {
  }

  emit(event: string, data: any) {
    this.socket.emit(event, data);
  }

  fromEvent(event: string): Observable<any>{
    return this.socket.fromEvent(event);
  }
  disconnect() {
    this.socket.disconnect();
  }
}

app.config.ts

import { ApplicationConfig, provideZoneChangeDetection, importProvidersFrom } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatListModule } from '@angular/material/list';
import { MatSnackBarModule } from '@angular/material/snack-bar';

import { routes } from './app.routes';
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { SocketIoModule, SocketIoConfig } from 'ngx-socket-io';
const config: SocketIoConfig = { url: 'ws://localhost:1234' };

export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes),
    provideHttpClient(withFetch()), 
    provideClientHydration(withEventReplay()), provideAnimationsAsync(),
    importProvidersFrom(SocketIoModule.forRoot(config)),
  ]
};

Backend:

midi-player.gateway.ts

import {
  WebSocketGateway,
  WebSocketServer,
  SubscribeMessage,
  OnGatewayConnection,
  OnGatewayInit,
  OnGatewayDisconnect,
  MessageBody,
} from '@nestjs/websockets';
import { Server } from 'socket.io';
import { Logger } from '@nestjs/common';
//import * as MidiPlayer from 'midi-player-js';

@WebSocketGateway(1234)
export class MidiPlayerGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect{
  private readonly logger = new Logger(MidiPlayerGateway.name);
  private interval: NodeJS.Timeout;

  @WebSocketServer()
  server: Server;
  afterInit() {
    this.logger.log("Initialized");
  }

  handleConnection(client: any, ...args: any[]) {
    this.logger.log(`Client id:${client.id} connected`);
  }

  handleDisconnect(client: any) {
    this.logger.log(`Cliend id:${client.id} disconnected`);
  }
}

main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
  const app = await NestFactory.create(AppModule,
    {
      snapshot: true,
    }
  );
  await app.listen(process.env.PORT ?? 3000);
}
bootstrap();

When I serve the frontend, the browser hangs (spinning loading bar) with no errors in the console. The network inspect tab is also blank. However on the backend (Nest.js) logger I see the websocket connections being established when the browser is loaded:

enter image description here

I have tested the backend with Postman and I am able to connect to the socket.io server. Therefore, I believe the issue is with the frontend. I suspect that there is a conflict between the websocket and the standard HTTP requests to load content to my page. However I lack the experience to figure out where the issue could be.

I have tried the following to no avail: Receiving Error: xhr poll error socket.io client React, https://socket.io/docs/v4/handling-cors/

My issue also seems similar to this: https://www.reddit.com/r/angular/comments/1d2x98d/connecting_websocket_via_ngxsocketio_makes_whole/

My full code can be found here: https://github.com/RCPilot1604/Player-Piano-Server

Thank you in advance for anything can can point me in the right direction!

Upvotes: 1

Views: 51

Answers (0)

Related Questions