Customize ListView as chat window in Angular ListView component

12 Sep 202513 minutes to read

ListView can be customized as a chat window interface. To achieve this functionality, use the ListView template property and Avatar component.

* The ListView template property showcases the ListView as a chat window interface.
* The Avatar component designs the profile image of each contact person.

Refer to the template code snippet below for the chat window template implementation.

    <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

The ListView template renders list items with different layouts based on the chat property value from the data source. When chat equals “receiver”, the receiverTemplate displays the avatar on the left with message content on the right. For sender messages, the senderTemplate positions the avatar on the right with message content on the left, creating a typical chat conversation flow.

Adding messages to chat window

* Use a textbox to capture message input from the user.
* Add the textbox message to the ListView dataSource using the 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));