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

Creating a Conditional Structure in HTML: A Step-by-Step Guide

My website is in need of a form that can identify the user's role based on their name input. This feature is essential for individuals with private roles. Is it possible to achieve this using HTML alone, without relying on JavaScript? If not, what st ...

How can I dynamically change the prefix in an angular router?

In my Angular app, I have two main routes: dashboard and login: www.example.com/dashboard www.example.com/auth/login These routes are defined as follows: const routes = [ { path: 'dashboard', component: DashboardComponent }, { path: 'auth ...

The JavaScript function document.getElementById.onclick is not functioning as expected

One issue I am facing involves counting all downloads on my website. My current approach is to increment a value in my database each time a download button is clicked, and then display this value. Despite trying multiple methods, the download count always ...

Corner of the Border Revealing a Clear Sky above

Looking to enhance my navigation bar (menu) by adding a cornered border when the user hovers over it. <nav> <a href="#home">Home</a> | <a href="#about">About</a> | <a href="#blog">Blog</a ...

What are the ways to convert canvas animations into gif or webm formats?

I've written a function to capture each frame for the GIF, but I'm experiencing laggy output and crashes as the data increases. Any recommendations? function generateGifFromImages(imageList, frameRate, fileName, scaling) { gifshot.createGIF({ ...

Using ReactJS to create cross-browser inline styling with flexbox

I'm currently working on a React web application that relies heavily on inline styling. My goal is to ensure compatibility with the latest versions of major browsers (Safari, Chrome, Firefox, IE) while utilizing flexbox for layout. The issue I encou ...

Is it possible to implement middleware multiple times across various modules?

In my current setup, I have a module that is implementing a service and using specific middleware for processing. The issue arises when another module requires the same middleware, as each plugin operates independently and is not aware of other plugins&apo ...

I am looking for a way to batch upload several images from an HTML page to a nodejs server, where I can then rename and

Exploring the world of nodejs, I am seeking guidance on updating multiple images from HTML to node js. Specifically, how can I rename each image differently and save them to a directory? Alternatively, is there another solution that would better suit my ne ...

When utilizing the built-in filter in Angular 2 ag-grid, the Clear Filter button efficiently removes any text from the filter box without needing to refresh the

When using ag-Grid's default filter feature, I noticed that the clear filter button only clears the text box and does not automatically refresh the column, even when the 'clearButton' and 'applyButton' parameters are set to true. T ...

Is it possible to utilize the Wicket:id for generating CSS?

Can the wicket:id attribute of an element or component be used for CSS styling instead of the "class" attribute? For example: .tooltipster-arrow span, .column-shifter { display: block; width: 0; height: 0; position: absolute; } Let&apos ...

Webpack is failing to load the logo PNG image file

Is there a way to make the logo png file visible on the webpage? I have been encountering issues with loading the image while other elements like HTML, css, and fonts are loading properly when the web pack is started. List of Error Messages: Refused to a ...

The hidden absolute positioned div disappears once the sticky navbar becomes fixed on the page

Whenever my navbar reaches the top of the screen, the links in the dropdown menu disappear. I followed tutorials and examples from w3schools to build my webpage. Specifically: howto: js_navbar_sticky howto: css_dropdown_navbar This code snippet exempli ...

Achieving the incorporation of multiple components within a parent component using Angular 6

Within parent.component.html The HTML code I have implemented is as follows: <button type="button" class="btn btn-secondary (click)="AddComponentAdd()">Address</button> <app-addresse *ngFor="let addres of collOfAdd" [add]="addres">< ...

If the image is not found, add a count instead of showing a new one each time

I have implemented a function to retrieve the two-letter country code: $ipaddress = $_SERVER['REMOTE_ADDR']; function ip_details($ip) { $json = file_get_contents("http://ipinfo.io/{$ip}"); $details = json_decode($json); return $detai ...

I successfully corrected the selectable options list in HTML/CSS and am now working on linking it to a Django char field. I'm currently facing some difficulties in figuring out

Below is a Django form field I have defined: source_currency = forms.CharField(max_length=5) Here is an example of Select/Option HTML: <select name="fancySelect" for="{{ form.source_currency.id_for_label }}" class="makeMeFancy" id="drop1"> ...

What could be causing my "Swiper" component to malfunction in a TypeScript React project?

In my React project, I decided to incorporate the Swiper library. With multiple movie elements that I want to swipe through, I began by importing it as follows: import Swiper from 'react-id-swiper'; Utilizing it in my code like this: <div cla ...

Node.js Agent organizes my requests into pools

Currently I am working with node version v0.10.12 and am running performance tests on the server using Jmeter software to simulate multiple users accessing it. However, I have encountered an issue where when simulating more than 10 users, node.js pools my ...

The ng-model-options in Angular 2 is set to "updateOn: 'change blur'"

Currently working with angular 2, I am seeking a solution to modify the behavior of ngModel upon Enter key press. In angular 1.X, we utilized ng-model-options="{updateOn: 'change blur'}". How can this be achieved in angular 2? For reference, her ...

Performing numerous asynchronous MongoDB queries in Node.js

Is there a better way to write multiple queries in succession? For example: Space.findOne({ _id: id }, function(err, space) { User.findOne({ user_id: userid }, function(err, user) { res.json({ space: space, user: user}); }); }); It can g ...

Incorporate an image icon into an Angular grid

Currently, I am in the process of building a web application using Angular. The main goal is to create a grid and color specific cells based on data input. Below is the snippet of my HTML code: <mat-grid-list cols="10"> <mat-grid-tile * ...