Customize ListView as chat window in Angular ListView component

22 Jan 202513 minutes to read

ListView can be customizable as chat window. To achieve that, use ListView template property and Avatar component.

* ListView template property is used to showcase the ListView as chat window.
* Avatar component is used to design the image of contact person.

Refer the below template code snippet for Template of chat window.

        <ng-template #template let-data="">
            <div class="settings" *ngIf="data.chat!='receiver' then senderTemplate else receiverTemplate "></div>
            <ng-template #senderTemplate>
                <div id="content">
                    <div class="name"></div>
                    <div id="info"></div>
                </div>
                <div id="image" *ngIf="data.avatar!=''"><span class="e-avatar img1 e-avatar-circle"></span></div>
                <div id="image" *ngIf="data.avatar==''"><span class=" img1 e-avatar e-avatar-circle"> </span></div>
            </ng-template>

            <ng-template #receiverTemplate>
                <div id="image2" *ngIf="data.avatar!=''"><span class="e-avatar img2 e-avatar-circle"></span></div>
                <div id="image2" *ngIf="data.avatar==''"><span class=" img2 e-avatar e-avatar-circle"> </span></div>
                <div id="content1">
                    <div class="name1"></div>
                    <div id="info1"></div>
                </div>
            </ng-template>
        </ng-template>

Chat order in template

In ListView template, we have rendered the list items based on receiver and sender information from dataSource of ListView.

Adding messages to chat window

* Use textbox to get message from user.
* Add the textbox message to ListView dataSource using addItem method.
public btnClick() {
    let value = this.textboxEle.nativeElement.value;
    this.listObj.addItem([{ text: "Amenda", contact: value, id: "2", avatar: "A", pic: "", chat: "receiver" }]);
    this.textboxEle.nativeElement.value = "";
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { CommonModule } from '@angular/common';
import { Component, ViewChild } from '@angular/core';

@Component({
  imports: [ListViewModule, ButtonModule, CommonModule],
  standalone: true,
  selector: 'my-app',
  template: `
    <ejs-listview id='List' #list [dataSource]='data' headerTitle="Chat" showHeader="true" width="350px" [fields]='fields' height="200px">
  <ng-template #template let-data="">
    <div
      class="settings"
      *ngIf="
        data.chat != 'receiver';
        then senderTemplate;
        else receiverTemplate
      "
    ></div>
    <ng-template #senderTemplate>
      <div id="content">
        <div class="name"></div>
        <div id="info"></div>
      </div>
      <div id="image" *ngIf="data.avatar != ''">
        <span class="e-avatar img1 e-avatar-circle"></span>
      </div>
      <div id="image" *ngIf="data.avatar == ''">
        <span class=" img1 e-avatar e-avatar-circle"> </span>
      </div>
    </ng-template>
    <ng-template #receiverTemplate>
      <div id="image2" *ngIf="data.avatar != ''">
        <span class="e-avatar img2 e-avatar-circle"></span>
      </div>
      <div id="image2" *ngIf="data.avatar == ''">
        <span class=" img2 e-avatar e-avatar-circle"> </span>
      </div>
      <div id="content1">
        <div class="name1"></div>
        <div id="info1"></div>
      </div>
    </ng-template>
  </ng-template>
    </ejs-listview>
    <div style="width: 350px;margin: 0 auto;">
  <input
    #textbox
    id="name"
    style="width: 275px"
    class="e-input"
    type="text"
    placeholder="Type your message"
  />
  <button ejs-button id="btn" style="float:right" (click)="btnClick()">
    Send
  </button>
</div>
        `,
})
export class AppComponent {
  @ViewChild('list') listObj: any;
  @ViewChild('textbox') textboxEle: any;
  public data: Object[] = [
    {
      text: 'Jenifer',
      contact: 'Hi',
      id: '1',
      avatar: '',
      pic: 'pic01',
      chat: 'sender',
    },
    {
      text: 'Amenda',
      contact: 'Hello',
      id: '2',
      avatar: 'A',
      pic: '',
      chat: 'receiver',
    },
    {
      text: 'Jenifer',
      contact: 'What Knid of application going to launch',
      id: '4',
      avatar: '',
      pic: 'pic02',
      chat: 'sender',
    },
    {
      text: 'Amenda ',
      contact: 'A knid of Emergency broadcast App',
      id: '5',
      avatar: 'A',
      pic: '',
      chat: 'receiver',
    },
    {
      text: 'Jacob',
      contact: 'Can you please elaborate',
      id: '6',
      avatar: '',
      pic: 'pic04',
      chat: 'sender',
    },
  ];
  public fields = { text: 'Name' };
  public count = 1;
  public btnClick() {
    let value = this.textboxEle.nativeElement.value;
    this.listObj.addItem([
      {
        text: 'Amenda' + this.count.toString(),
        contact: value,
        id: (Math.random() * 1000).toFixed(0).toString(),
        avatar: 'A',
        pic: '',
        chat: 'receiver',
      },
    ]);
    this.listObj.dataBind();
    this.textboxEle.nativeElement.value = '';
    this.count++;
  }
}
@import 'node_modules/@syncfusion/ej2-base/styles/material.css';
@import 'node_modules/@syncfusion/ej2-angular-base/styles/material.css';
@import 'node_modules/@syncfusion/ej2-angular-lists/styles/material.css';
@import 'node_modules/@syncfusion/ej2-angular-buttons/styles/material.css';
@import 'node_modules/@syncfusion/ej2-layouts/styles/material.css';
@import 'node_modules/@syncfusion/ej2-angular-layouts/styles/material.css';
@import 'node_modules/@syncfusion/ej2-inputs/styles/material.css';
@import 'node_modules/@syncfusion/ej2-angular-inputs/styles/material.css';

#container {
    visibility: hidden;
}

#loader {
    color: #008cff;
    height: 40px;
    width: 30%;
    position: absolute;
    font-family: 'Helvetica Neue', 'calibiri';
    font-size: 14px;
    top: 45%;
    left: 45%;
}

#List {
    margin: 0 auto;
    border: 1px solid #ccc;
}

#List .e-list-item {
    height: auto;
    cursor: pointer;
}

#List .e-list-header .e-text {
    font-family: sans-serif;
    font-size: 18px;
    line-height: 26px;
}

#List #info,
#List .name {
    font-size: 11px;
    line-height: 20px;
}

#List .name {
    padding-top: 3px;
    font-weight: 500;
    padding-left: 150px;
}

#List #info {
    float: right;
    margin-right: 10px;
}

.pic01 {
    background-image: url('https://ej2.syncfusion.com/demos/src/grid/images/1.png');
}

.pic02 {
    background-image: url('https://ej2.syncfusion.com/demos/src/grid/images/3.png');
}

.pic03 {
    background-image: url('https://ej2.syncfusion.com/demos/src/grid/images/5.png');
}

.pic04 {
    background-image: url('https://ej2.syncfusion.com/demos/src/grid/images/2.png');
}

/* csslint ignore:start */
.img2 {
    margin-left: 10px;
    margin-top: 2px !important;
    font-size: 13px;
}

#List #content1 {
    width: 200px;
    background-color: aliceblue;
    display: inline-block;
    margin: 5px;
}

#List #info1,
#List .name1 {
    font-size: 11px;
    line-height: 20px;
    margin-left: 10px;
}

#List .name1 {
    padding-top: 3px;
    font-weight: 500;
}

#List #content {
    margin: 5px;
    width: 200px;
    margin-left: 75px;
    background-color: aliceblue;
    display: inline-block;
}

#image {
    float: right;
}

#image2 {
    float: left;
}

.img1 {
    margin-right: 10px;
    margin: 5px;
    font-size: 13px;
}

.e-listview .e-list-item {
    padding: 0 !important;
}

.e-listview .e-list-header {
    color: white !important;
}

.e-listview .e-list-header {
    background: rgb(2, 120, 215) !important;
}

#List.e-listview .e-hover {
    background-color: transparent;
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));