Displaying messages in an Angular 2 chatbox from the bottom to the top

As a newcomer to using typescript, I am currently working on an angular 2 project and facing some challenges with creating a chatbox. My goal is to have new messages displayed at the bottom while pushing the old ones up one line at a time, as shown in this example:

I also want to ensure that the messages stay within the div container and when it reaches full capacity, I would like a scroll feature to view older messages.

This is the current setup I have:

chatroom.component.html:

<h2>Player Notifications</h2>
  <p *ngFor="let m of playersChannel">{{m}}</p>

<h2>Chat history</h2>
<div class='chatbox'>
  <p *ngFor="let m of chatChannel">{{m}}</p>
</div>

chatroom.component.css:

.chatbox{
    width: 100%;
    height: 500px;
}

.chatbox p{ 
    text-align: bottom;

}

chatroom.component.ts:

import { Component, OnInit } from '@angular/core';

import {WebSocketService } from './websocket.service';

@Component({
    moduleId: module.id,
    selector: 'chat',
    styleUrls: [ 'chatroom.component.css' ],
    templateUrl: 'chatroom.component.html'
})
export class ChatroomComponent implements OnInit {
    playersChannel: string[] = [];
    chatChannel: string[] = [];    

    constructor(private websocketService: WebSocketService){
    }

    ngOnInit() {
        this.websocketService
            .getChatMessages()
            .subscribe((m:any) => this.chatChannel.push(<string>m));
        this.websocketService
            .getPlayersMessages()
            .subscribe((m:any) => this.playersChannel.push(<string>m));
    }

}

websocket.service.ts:

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';

import {Observable} from 'rxjs/Observable';

import * as io from 'socket.io-client';

@Injectable()
export class WebSocketService {
    private socket: SocketIOClient.Socket;
    constructor() {
        if (!this.socket) {
            this.socket = io(`http://${window.location.hostname}:${window.location.port}`);
        }
    }

    sendChatMessage(message: any) {
        this.socket.emit('chat', this.getUserTime() + message);
    }

    getPlayersMessages(): Observable<any> {
        return this.createObservable('players');
    }

    getChatMessages(): Observable<any> {
        return this.createObservable('chat');
    }

     getUserTime(){
         let now = Date.now();
         let date = new Date(now);
         let hours = date.getHours();
         let mins = date.getMinutes();
         let secs = date.getSeconds();
        return hours + ":" + mins + ":" + secs + ": ";
    } 

    private createObservable(channel: string): Observable<any> {
        return new Observable((observer:any) => {
            this.socket.on(channel, (data:any) => {
                observer.next(data);
            });
            return () => this.socket.disconnect();
        });

    }
}

server.websocket.ts:

const io = require('socket.io');

export class WebSocketServer {
    public io: any;




    public init = (server: any) => {
        this.io = io.listen(server);
        this.io.sockets.on('connection', (client: any) => {
            client.emit('players', Date.now() + ': Welcome to battleship');
            client.broadcast.emit('players', Date.now() + ': A new player has arrived');
            client.on('chat', (data) => this.io.emit('chat', data));

        });
    };
   public notifyAll = (channel: string, message: any) => {
        this.io.sockets.emit(channel, message);
    };


};

Answer №1

To change the order of messages, you can simply rearrange the array by sorting it based on criteria such as added date or array index. Another option is to use unshift instead of push to add new messages to the beginning of the array.

For a sample code snippet on how to organize messages, check out this link: angular 2 sort and filter

You can also position the messages at the bottom of the screen or container by using CSS:

.chatbox{
  display:table;
}
.chatbox p{
  display:table-cell;
  vertical-align:bottom;
}

Answer №2

If you're looking for a pure CSS solution, here's what you can do. Set a fixed height for div.message-container and include overflow-y: auto in its styles. To ensure the messages are always at the bottom of the container, apply position: relative to the container and position: absolute; bottom: 0 to each message within it.

Here's an example:

.message-container {
    height: 300px; /* adjust as needed */
    overflow-y: auto;
    position: relative;
}

.message-container .message {
    position: absolute;
    bottom: 0;
}

If you want to reverse the order of the messages, consider creating your custom pipe or using one from an Angular module like ng-pipes. Here's an example using a custom pipe:

@Pipe({
  name: 'reverse'
})
export class ReversePipe {
  transform(messages) {
    return messages.slice().reverse();
  }
}

Hope this helps!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Reveal and conceal information with a customized web address

I have a PHP and MySQL blog that I want to display in a div using show and hide JavaScript functions. Everything works fine with other divs, but the issue arises when clicking on a vanity URL causing my webpage to refresh every time it's clicked. The ...

iOS does not support Css3 Transition

My Transition Code works on PC and android devices, but it does not work on iOS devices. I am only using HTML and CSS. /***** BOX 3 *****/ #box3 { height:240px; width:198px; border:1px solid #dedede; background-color:#fcfcfc; position:relative; overflow:h ...

Unusual behavior in ReactJS and HTML5 video player observed

I currently have two React presentation components that include HTML5 video tags. The first component, named Homepage, is as follows: export default class Homepage extends React.Component { render() { return( <div className="Homepage"> ...

Accessing getUserMedia within Internet Explorer 11 or utilizing MediaStream on IE 11

I am attempting to utilize the getUserMedia function in IE 11 with the help of the temasys plugin. However, IE does not support the MediaStream instance returned by getUserMedia. Below is a snippet of my code: import React from 'react' import { ...

The E.js Template encountered an error with an unexpected token "else"

I am in the process of creating a website quickly using e.js & Express. However, I am encountering some problems when trying to use an if-else statement within e.js tags. The if statement works fine, but as soon as I add an else statement, things start t ...

The combination of two colors in a hard background fails to create an appealing aesthetic

Seeking assistance with an issue I encountered while trying to create a two-color background. Below is the code snippet: body, html { height: 100%; width: 100%; background: #0000ff; background: linear-gradient(180deg, #ff0000 50%, #0000f ...

Anticipate the absence of a specific object length

I have an Object that I need to test for null: getLastTeamUpdatedItemLogBuffer(): IBufferElement { const storageItems = this.storageSvc.getItem(StorageKey.lastTeamUpdatedItem, true) as IBufferElement; return storageItems || null; } This is the IBufferE ...

Get your hands on a complimentary Angular 2 scheduling tool

I am in need of integrating a scheduler into my angular 2 application. My goal is to schedule various employees within a day view and I found two paid components that might work for me: FullCalendar Scheduler Demo Bryntum Angular 2 Scheduler Currently, ...

Evaluate numerical values using xsl:choose function

Using XSL version 1.0, I am populating an HTML table with percentage values from XML. My goal is to display the highlighted color of the percentages based on a condition, but the condition is not being processed as expected, leading to the exclusion of the ...

What is the best way to establish the routes properly?

Below is a code snippet for reference: var x = require('./folder/usefile'); var Auth = passport.authenticate('jwt', { session: false }); module.exports = function(app){ console.log('inside function(app)'); / ...

DIV collapsing in reverse order from the bottom to the top

Looking for some help on how to create two links that, when clicked, will scroll a hidden <div> up to fill the full height of its parent container. I've been having trouble with the element using the full height of the <BODY> instead. ...

Tips for troubleshooting or modifying a dependency that exclusively consists of type declaration files

I am currently facing a challenge where I need to access and debug/change the code of one of our dependencies that contains custom Angular components from a separate repository. This particular repository is being included via a self-hosted npm registry wi ...

Retrieving JSON data in Angular 5 returns a 400 bad request error

Having trouble calling the REST API of Amazon S3 from Angular 5. Keep getting a 400 bad request error. This problem has been persisting for a while now and I really need to find a solution or at least get some suggestions on where the issue might be. Her ...

What is the significance of the .jpg?t= in the URL?

This webcam image displays the code ?t=1512496926. What exactly does this code signify? Could it be related to time? Is it just a random string of characters? https://i.stack.imgur.com/ZAZMy.jpg ...

What is the proper way to provide parameters for express.use to avoid encountering a type error?

When attempting to use the path string in this code snippet within the function, an error is thrown. The argument type string cannot be assigned to the parameter type RequestHandler<RouteParameters>    The assigned type does not contain call si ...

Combining two HTML tables in PHP: A step-by-step guide

I have two HTML tables that each contain three rows and one column. I am looking to combine them programmatically in order to create a single table with two columns and three rows. Is there a specific function or workaround that can help me achieve this? ...

Information is not transferring to Bootstrap modal

I attempted to send a value to a modal by following the instructions on the Bootstrap documentation here. However, I am facing an issue where the data is not being successfully passed. To trigger the modal, use the following button: <button type=" ...

Modifying the border hue of Material-UI's Select Component

Here is the Select component I've created using materials-UI <FormControl variant="outlined"> <Select value={this.state.value} onChange = {this.handleChange} className={this.props.classes.select} inputProps = {{class ...

Guide: Populating an MUI Autocomplete TextField using data fetched from Axios

I have created a registration form for pets which includes an MUI Autocomplete component in the text field for selecting the pet type. However, I am facing an issue when trying to pre-fill the Autocomplete component with data from the database while edit ...

Stylesheets per module in Angular 2

For my website design, I've decided to adopt a modular structure using sass. To ensure consistency throughout the module, instead of defining stylesheets at the component level, I plan to define them at the module level and import them into each compo ...