onTheInternet
onTheInternet

Reputation: 7263

How do I receive messages from websocket server and populate angular component

I am learning how to incorporate live chat into an Angular project using Socket.IO and following This tutorial I found

I incorporated an input box into my component and now I'm successfully sending a message from the component to the server.

Chat server working

The problem that I'm running into is that I don't know how to use the emit send the message back to the user and update the DOM.

I'll run through my code. The chat box doesn't have its own component but eventually, it will. Here is the typescript code for where the chatbox lives. I'm creating a card game so you'll notice references to decks and dealers.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { DealerService } from '../services/dealer.service';
import { ChatService } from '../services/chat.service';


@Component({
  selector: 'app-blackjackgame',
  templateUrl: './blackjackgame.component.html',
  styleUrls: ['./blackjackgame.component.css']
})
export class BlackjackgameComponent implements OnInit, OnDestroy {

  constructor(private dealer: DealerService, private chat: ChatService) { }

  ngOnInit() {
    this.dealer.generateDeck();
    this.dealer.shuffle(5);
    this.chat.messages.subscribe(msg => {
      console.log(msg);
    });

  }

  // This is now working
  sendMessage(message: string) {
    this.chat.sendMsg(message);
  }


  // Is this proper way to do this? I'm not sure
  updateMessages(message: string) {
    console.log('message was emitted: ' + message);
  }

  ngOnDestroy() {
    // no longer needed since generateDeck has it's own destroy
    // this.deckService.destroy_deck();
  }

}

I have two main services, chat service, and WebSocket service.

The chat service looks like this

import { Injectable } from '@angular/core';
import { WebsocketService } from './websocket.service';
import { Observable, Subject } from 'rxjs/Rx';

@Injectable()
export class ChatService {

  messages: Subject<any>;

  constructor(private wsService: WebsocketService) {
    this.messages = <Subject<any>>wsService
      .connect()
      .map((response: any): any => {
      return response;
    });
  }

  sendMsg(msg){
    this.messages.next(msg);
  }

}

And my WebSocket service looks like this

import { Injectable } from '@angular/core';
import * as io from 'socket.io-client';
import { Observable } from 'rxjs/Observable';
import * as Rx from 'rxjs/Rx';
import { environment } from '../../environments/environment';


@Injectable()
export class WebsocketService {

  private socket; // socket that connects to our socket.io server
  constructor() { }

  connect(): Rx.Subject<MessageEvent> {
    this.socket = io(environment.ws_url);

    const observable = new Observable(observer => {
      this.socket.on('message', (data) => {
        console.log('Received a message from websocket service');
        observer.next(data);
      });
      return () => {
        this.socket.disconnect();
      };
    });

    const observer = {
      next: (data: Object) => {
        this.socket.emit('message', JSON.stringify(data));
      }
    };

    return Rx.Subject.create(observer, observable);
  }

}

And finally, I have a websocket server written in plain javascript. You've seen part of it in my photo above. The full code looks like this

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);



/*io.on('connection', function(socket){
    console.log('Connection made');
    socket.on('chat message', function(msg){
        io.emit('chat message', msg);
    });
});*/

io.on('connection', function(socket){
    console.log('connection');
    socket.on('message', function(message){
        console.log('Message received: ' + message);
        io.emit('message', {type:'new-message', text:message});
    })
})

http.listen(5000, function(){
  console.log('listening on *:5000');
});

So again, I have my websocket server logging when it receives a message. My question is, how do I go back the other way? I want to update my DOM in the component with the new message based on the emitted message from the WebSocket. Any suggestions will be greatly appreciated; I'm very new to this.

Upvotes: 2

Views: 8790

Answers (1)

onTheInternet
onTheInternet

Reputation: 7263

So I figured out the answer. I was pretty close. I created a new chat component. Here is the code for that.

Chatbox component HTML

<div id="chatDisplay">
  <ul>
    <li *ngFor = "let msg of messages">{{msg}}</li>
  </ul>
</div>
<div id="chatInput">
  <input type="text" id="chatBox" #chatMessage>
  <button (click)="sendMessage(chatMessage.value)">Send Message</button>
</div>

Chatbox component typescript

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ChatService } from '../services/chat.service';
import { Observable, Subject } from 'rxjs/Rx';

@Component({
  selector: 'app-chatbox',
  templateUrl: './chatbox.component.html',
  styleUrls: ['./chatbox.component.css']
})
export class ChatboxComponent implements OnInit, OnDestroy {

  messages = [];
  constructor(private chat: ChatService) { }

  ngOnInit() {
    this.chat.messages.subscribe(msg => {
      this.messages.push(msg.text);
    });
  }

  sendMessage(message: string){
    this.chat.sendMsg(message);
  }

  ngOnDestroy() {
  }

}

Upvotes: 3

Related Questions