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));