Search results

How To

Get selected items in the ListView component

Single or many items can be selected by users in the ListView component. An API is used to get selected items from the list items. This is called as the getSelectedItems method.

getSelectedItems method

This is used to get the details of the currently selected item from the list items. It returns the SelectedItem | SelectedCollection

The getSelectedItems method returns the following items from the selected list items.

Return type Purpose
text Returns the text of selected item lists
data Returns the whole data of selected list items, i.e., returns the fields data of selected li.
item Returns the collections of list items
Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component,ViewChild } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<ejs-listview #listview id='sample-list' [dataSource]='data' [showCheckBox]=true [fields]='fields'></ejs-listview>
    <br/>
    <input type="button" id="btn" ejs-button value="Get Selected Items" (click)="onClick($event)" />
     <div #val id="val">
     </div>`
})

export class AppComponent {
    @ViewChild('listview') element:any;
    @ViewChild('val') valEle:any;
    public data: Object = [
    { text: 'Hennessey Venom', id: 'list-01' },
    { text: 'Bugatti Chiron', id: 'list-02', isChecked: true },
    { text: 'Bugatti Veyron Super Sport', id: 'list-03'},
    { text: 'SSC Ultimate Aero', id: 'list-04', isChecked: true  },
    { text: 'Koenigsegg CCR', id: 'list-05' },
    { text: 'McLaren F1', id: 'list-06' },
    { text: 'Aston Martin One- 77', id: 'list-07', isChecked: true },
    { text: 'Jaguar XJ220', id: 'list-08' }
];
public fields: Object = { id: 'id', isChecked:'isChecked'};

onClick(event){
  let selecteditem =this.element.getSelectedItems();
  this.valEle.nativeElement.innerHTML="";
 for(let i=0; i< selecteditem["data"].length; i++) {
  let listData = document.createElement('p');
  listData.innerHTML = "text : "+ selecteditem["text"][i]+" , "+"id : "+selecteditem["data"][i].id;
  this.valEle.nativeElement.append(listData);
 }
}



{% endraw %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Use dynamic templates of ListView based on device

The Syncfusion Essential JS2 components are desktop and mobile-friendly. So, you can use Syncfusion components in both modes. The component templates are not always fixed. Applications may need to load various templates depending upon the device.

Integration

In the ListView component, template support is being used. In some cases, the component wrapper is always responsive across all devices, but the template contents are dynamically changed with unspecified (sample side) dimensions. CSS customization is also needed in sample-side to align template content responsively in both mobile and desktop modes. Here, two templates have been loaded for mobile and desktop modes. To check the device mode, a browser module has been imported from the ej2-base package.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component} from '@angular/core';
import { Browser } from '@syncfusion/ej2-base';

@Component({
    selector: 'my-app',
    template: `<ejs-listview id='List' [dataSource]='dataSource' [template]='templatecheck ? mob_template : win_template' headerTitle='Syncfusion Blog' [showHeader]='true'>
        <ng-template #mob_template let-dataSource="">
    <div class="settings">
        <div id="postContainer">
            <div id="postImg">
                <img src={{dataSource.image}} /></div>
            <div id="content">
                <div id="info">
                    <div id="logo">
                        <div id="share">
                            <span class="share"></span> </div>
                        <div id="comments"> <span class="comments"></span> </div>
                        <div id="bookmark"> <span class="bookmark"></span> </div>
                    </div>
                </div>
                <div class="name">{{dataSource.Name}}</div>
                <div class="description">{{dataSource.content}}</div>
                <div class="timeStamp">{{dataSource.timeStamp}} </div>
            </div>
        </div>
    </div>
</ng-template>
<ng-template #win_template let-dataSource="">
    <div class="settings">
        <div id="postContainer">
            <div id="postImg">
                <img src={{dataSource.image}} /></div>
            <div id="content">
                <div class="name">{{dataSource.Name}}</div>
                <div class="description">{{dataSource.content}}</div>
                <div id="info">
                    <div id="logo">
                        <div id="share">
                            <span class="share"></span> </div>
                        <div id="comments"> <span class="comments"></span> </div>
                        <div id="bookmark"> <span class="bookmark"></span> </div>
                    </div>
                    <div class="timeStamp">{{dataSource.timeStamp}} </div>
                </div>
            </div>
        </div>
    </div>
</ng-template></ejs-listview>`
})

export class AppComponent {
   //Define an array of JSON data
    public dataSource: any = [
        { Name: 'IBM Open-Sources Web Sphere Liberty Code', content: 'In September, IBM announced that it would be open-sourcing the code for WebSphere...', id: '1', image: 'https://ej2.syncfusion.com/demos/src/listview/images/1.png', timeStamp: 'Syncfusion Blog - October 19, 2017' },
        { Name: 'Must Reads: 5 Big Data E-books to upend your development', content: 'Our first e-book was published in May 2012-jQuery Succinctly was the start of over...', id: '2', image: 'https://ej2.syncfusion.com/demos/src/listview/images/2.png', timeStamp: 'Syncfusion Blog - October 18, 2017'  },
        { Name: 'The Syncfusion Global License: Your Questions, Answered ', content: 'Syncfusion recently hosted a webinar to cover the ins and outs of the Syncfusion global...', id: '4', image: 'https://ej2.syncfusion.com/demos/src/listview/images/3.png', timeStamp: 'Syncfusion Blog - October 18, 2017'  },
        { Name: 'Know: What is Coming from Microsoft this Fall ', content: 'On October 17, Microsoft will release its Fall Creators Update for the Windows 10 platform...', id: '5', image: 'https://ej2.syncfusion.com/demos/src/listview/images/6.png', timeStamp: 'Syncfusion Blog - October 17, 2017'  }
    ];
public fields: Object = { text: 'Name' };
public templatecheck:boolean;
constructor(){
    this.templatecheck = Browser.isDevice;
}
}



{% endraw %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Load list items in child list dynamically

To load list items in child list dynamically, push the new list item data into the existing dataSource using the select event.

Refer to the following steps to load list item into the child list:

  1. Initially, render the ListView with the required data source.

  2. Bind the select event that triggers selecting list item in the ListView component. By using the select event, you can push the new list item to the child list of the data source on specifying its item index. Item index can be obtained from the SelectEventArgs of the select event.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewEncapsulation } from '@angular/core';
import { SelectEventArgs } from '@syncfusion/ej2-lists';

@Component({
    selector: 'my-app',
    template: `<ejs-listview id='listview' [dataSource]='dataSource' [template]='wintemplate' headerTitle='Folders' [showHeader]='true' [showIcon]='true' [fields]='fields' (select)='onSelect($event)'></ejs-listview>
    `
    styles: [`
    #listview {
    display: block;
    max-width: 400px;
    margin: auto;
    border: 1px solid #dddddd;
    border-radius: 3px;
}


#listview.e-listview .e-list-icon {
    height: 24px;
    width: 30px;
}

.folder, .file  {
    background: url('http://ej2.syncfusion.com/demos/src/listview/images/file_icons.png') no-repeat;
    background-size: 300%;
}

.folder{
    background-position: -5px -460px;
}

.file {
    background-position: -5px -151px;
}

.list {
    color:deeppink !important;
}
`],
encapsulation: ViewEncapsulation.None
})

export class AppComponent {


public dataSource: { [key: string]: Object }[] = [
    {
        id: '01', text: 'Music', icon: 'folder',
        child: [
            { id: '01-01', text: 'Gouttes.mp3', icon: 'file' }
        ]
    },
    {
        id: '02', text: 'Videos', icon: 'folder',
        child: [
            { id: '02-01', text: 'Naturals.mp4', icon: 'file' },
            { id: '02-02', text: 'Wild.mpeg', icon: 'file' },
        ]
    },
    {
        id: '03', text: 'Documents', icon: 'folder',
        child: [
            { id: '03-01', text: 'Environment Pollution.docx', icon: 'file' },
            { id: '03-02', text: 'Global Water, Sanitation, & Hygiene.docx', icon: 'file' },
            { id: '03-03', text: 'Global Warming.ppt', icon: 'file' },
            { id: '03-04', text: 'Social Network.pdf', icon: 'file' },
            { id: '03-05', text: 'Youth Empowerment.pdf', icon: 'file' },
        ]
    },
    {
        id: '04', text: 'Pictures', icon: 'folder',
        child: [
            {
                id: '04-01', text: 'Camera Roll', icon: 'folder',
                child: [
                    { id: '04-01-01', text: 'WIN_20160726_094117.JPG', icon: 'file' },
                    { id: '04-01-02', text: 'WIN_20160726_094118.JPG', icon: 'file' },
                    { id: '04-01-03', text: 'WIN_20160726_094119.JPG', icon: 'file' }
                ]
            },
            {
                id: '04-02', text: 'Wind.jpg', icon: 'file'
            },
            {
                id: '04-02', text: 'Stone.jpg', icon: 'file'
            },
            {
                id: '04-02', text: 'Home.jpg', icon: 'file'
            },
            {
                id: '04-02', text: 'Bridge.png', icon: 'file'
            }
        ]
    },
    {
        id: '05', text: 'Downloads', icon: 'folder',
        child: [
            { id: '05-01', text: 'UI-Guide.pdf', icon: 'file' },
            { id: '05-02', text: 'Tutorials.zip', icon: 'file' },
            { id: '05-03', text: 'Game.exe', icon: 'file' },
            { id: '05-04', text: 'TypeScript.7z', icon: 'file' },
        ]
    },
];

public  fields: Object = { iconCss: 'icon', tooltip: 'text' };

//Select event to add new list item in child page
onSelect(args: SelectEventArgs) {
    //Add new file to the child page of selected list item
    this.dataSource[args.index].child.push({ id: '01-02', text: 'Newly Added File', icon: 'file', htmlAttributes: { role: 'li', class: 'list' } });
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

List Items Count in Group Header

The ListView component supports wrapping list items into a group based on the category. The category of each list item can be mapped with groupBy field of the data source. You can display grouped list items count in the list-header using the group header template. Refer to the following code sample to display grouped list item count.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component} from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<ejs-listview id='List' [dataSource]='dataSource' cssClass='e-list-template' [fields]='fields'>
      <ng-template #template let-dataSource="">
        <div class="e-list-wrapper e-list-multi-line e-list-avatar">
            <img class="e-avatar e-avatar-circle" src={{dataSource.image}} style="background:#BCBCBC" />
            <span class="e-list-item-header">{{dataSource.Name}}</span>
            <span class="e-list-content">{{dataSource.contact}}</span>
        </div>
      </ng-template>
  </ejs-listview>`
})

export class AppComponent {
    public dataSource: Object = [
        { Name: 'Nancy', contact:'(206) 555-985774', id: '1', image: 'https://ej2.syncfusion.com/demos/src/grid/images/1.png',  category: 'Experience'},
        { Name: 'Janet', contact: '(206) 555-3412', id: '2', image: 'https://ej2.syncfusion.com/demos/src/grid/images/3.png', category: 'Fresher' },
        { Name: 'Margaret', contact:'(206) 555-8122', id:'4', image: 'https://ej2.syncfusion.com/demos/src/grid/images/4.png', category: 'Experience' },
        { Name: 'Andrew ', contact:'(206) 555-9482', id: '5', image: 'https://ej2.syncfusion.com/demos/src/grid/images/2.png' category: 'Experience'},
        { Name: 'Steven', contact:'(71) 555-4848', id: '6', image: 'https://ej2.syncfusion.com/demos/src/grid/images/5.png', category: 'Fresher' },
        { Name: 'Michael', contact:'(71) 555-7773', id: '7', image: 'https://ej2.syncfusion.com/demos/src/grid/images/6.png', category: 'Experience' },
        { Name: 'Robert', contact:'(71) 555-5598', id: '8', image: 'https://ej2.syncfusion.com/demos/src/grid/images/7.png', category: 'Fresher' },
        { Name: 'Laura', contact:'(206) 555-1189', id: '9', image: 'https://ej2.syncfusion.com/demos/src/grid/images/8.png', category: 'Experience' },
    ];

    public fields: Object = { text: 'Name', groupBy: 'category' };
}



{% endraw %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Customize ListView as mobile contact layout

You can customize the ListView using the template property. Refer to the following steps to customize ListView as mobile contact view with our ej2-avatar.

  • Render the ListView with dataSource that has avatar data. You can set avatar data as either text or class names. Refer to the following codes.
let data: any = [
    {
    text: "Jenifer",
    contact: "(206) 555-985774",
    id: "1",
    avatar: "",
    pic: "pic01"
  },
  { text: "Amenda", contact: "(206) 555-3412", id: "2", avatar: "A", pic: "" },
];
  • Set avatar classes in ListView template to customize contact icon. In the following codes, medium size avatar has been set using the class name e-avatar e-avatar-circle from data source.

{% raw %}

  <ng-template #template let-data="">
                <div class="e-list-wrapper e-list-multi-line e-list-avatar">
                    <span class="e-avatar e-avatar-circle" *ngIf="data.avatar !== ''">{{data.avatar}}</span>
                    <span class="{{data.pic}} e-avatar e-avatar-circle" *ngIf="data.pic !== '' "> </span>
                    <span class="e-list-item-header">{{data.text}}</span>
                    <span class="e-list-content">{{data.contact}}</span>
                </div>
    </ng-template>

{% endraw %}

Avatars can be set in different sizes in avatar classes. To know more about avatar classes, refer to Avatar.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
    <div id="sample">
        <ejs-listview id='List' [dataSource]='data' headerTitle='Contacts' cssClass='e-list-template' [showHeader]='true' sortOrder='Ascending'>
            <ng-template #template let-data="">
                <div class="e-list-wrapper e-list-multi-line e-list-avatar">
                    <span class="e-avatar e-avatar-circle" *ngIf="data.avatar !== ''">{{data.avatar}}</span>
                    <span class="{{data.pic}} e-avatar e-avatar-circle" *ngIf="data.pic !== '' "> </span>
                    <span class="e-list-item-header">{{data.text}}</span>
                    <span class="e-list-content">{{data.contact}}</span>
                </div>
            </ng-template>
        </ejs-listview>
    </div>
    `
})

export class AppComponent {
     // Listview datasource with avatar and image source fields
     public data: { [key: string]: Object; }[] = [
  {
    text: "Jenifer",
    contact: "(206) 555-985774",
    id: "1",
    avatar: "",
    pic: "pic01"
  },
  { text: "Amenda", contact: "(206) 555-3412", id: "2", avatar: "A", pic: "" },
  {
    text: "Isabella",
    contact: "(206) 555-8122",
    id: "4",
    avatar: "",
    pic: "pic02"
  },
  {
    text: "William ",
    contact: "(206) 555-9482",
    id: "5",
    avatar: "W",
    pic: ""
  },
  {
    text: "Jacob",
    contact: "(71) 555-4848",
    id: "6",
    avatar: "",
    pic: "pic04"
  },
  { text: "Matthew", contact: "(71) 555-7773", id: "7", avatar: "M", pic: "" },
  {
    text: "Oliver",
    contact: "(71) 555-5598",
    id: "8",
    avatar: "",
    pic: "pic03"
  },
  {
    text: "Charlotte",
    contact: "(206) 555-1189",
    id: "9",
    avatar: "C",
    pic: ""
  }
];

}



{% endraw %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Filter list items in the ListView component

The filtered data can be displayed in the ListView component depending upon on user inputs using the DataManager. Refer to the following steps to render the ListView with filtered data.

  • Render a textbox to get input for filtering data.

  • Render ListView with dataSource, and set the sortOrder property.

  • Bind the keyup event for textbox to perform filtering operation. To filter list data, pass the list data source to the DataManager, manipulate the data using the executeLocal method, and then update filtered data as ListView dataSource.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild } from "@angular/core";
import { enableRipple } from "@syncfusion/ej2-base";
import { DataManager, Query, ODataV4Adaptor } from "@syncfusion/ej2-data";
enableRipple(true);

@Component({
    selector: 'my-app',
    template: `<div id="sample">
            <input #textbox class="e-input" type="text" id="textbox" placeholder="Filter" title="Type in a name" (keyup)=onkeyup($event) />
            <ejs-listview #list id='list' [dataSource]='listData' [fields]='fields' [sortOrder]='Ascending'></ejs-listview>
        </div>`,
        styles: [`
        #list {
  box-shadow: 0 1px 4px #ddd;
  border-bottom: 1px solid #ddd;
}
#sample {
  height: 220px;
  margin: 0 auto;
  display: table;
}
        `]
})

export class AppComponent {
    public listData: Object = [
  { text: "Hennessey Venom", id: "list-01" },
  { text: "Bugatti Chiron", id: "list-02" },
  { text: "Bugatti Veyron Super Sport", id: "list-03" },
  { text: "SSC Ultimate Aero", id: "list-04" },
  { text: "Koenigsegg CCR", id: "list-05" },
  { text: "McLaren F1", id: "list-06" }
];

 public fields: Object = { text: "text", id: "id" };
   @ViewChild('list')
   listObj: ListViewComponent;
   @ViewChild('textbox')textboxEle: any;
    onkeyup(event){
      let value = this.textboxEle.nativeElement.value;
      let data = new DataManager(this.listData).executeLocal(new Query().where("text", "startswith", value, true));
  if (!value) {
    this.listObj.dataSource = this.listData.slice();
  } else {
    this.listObj.dataSource = data;
  }
  this.listObj.dataBind();
    }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

In this demo, data has been filtered with starting character of the list items. You can also filter list items with ending character by passing the endswith in where clause instead of startswith.

Trace all events in ListView

The ListView component triggers events based on its actions. The events can be used as extension points to perform custom operations. Refer to the following steps to trace the ListView events:

  1. Render the ListView with dataSource, and bind the actionBegin, actionComplete, and select events.

  2. Perform custom operations in actionBegin, actionComplete, and select events.

  3. Provide event log details for actionBegin and actionComplete events, and they will be displayed in the event trace panel when the ListView action starts and the dataSource bound successfully.

  4. Get the selected item details from the SelectEventArgs in the select event, and display the selected list item text in the event trace panel while selecting list items.

  5. Use clear button to remove event trace information.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild, ViewEncapsulation } from "@angular/core";
import { SelectEventArgs } from "@syncfusion/ej2-lists";
@Component({
    selector: 'my-app',
    template: `<div id="sample">
      <div class="content-wrapper">
    <ejs-listview id='listview-def' [dataSource]='listData' [width]='250' (select)='onSelect($event)' (actionBegin)='onActionBegin($event)' (actionComplete)='onActionComplete($event)'></ejs-listview>
         </div>
         <div id="list_event">
                <h4><b>Event Trace</b></h4>
                <div id="evt">
                    <div class="eventarea" style="height:273px;overflow: auto">
                        <span #EventLog class="EventLog" id="EventLog" style="word-break: normal;"></span>
                    </div>
                    <div class="evtbtn">
                        <input ejs-button id="clear" type="button" value="Clear" (click)='onclick($event)'>
                    </div>
                </div>
            </div>
        </div>`,
        styles: [`
       #EventLog b {
  color: #388e3c;
}

#listview-def {
  border: 1px solid #dcdcdc;
}
.content-wrapper {
  padding-left: 40px;
  padding-top: 36px;
}

.evtbtn {
  margin-top: 40px;
  margin-left: 70px;
}

/* csslint ignore:start */

hr {
  margin-top: 6px !important;
  margin-bottom: 6px !important;
}

/* csslint ignore:end */

#evt {
  border: 1px solid #dcdcdc;
  padding: 10px;
  min-width: 10px;
}

#sample {
  display: inline-flex;
}

.eventarea {
  min-width: 250px;
}

#list_event {
  margin-top: -25px;
  padding-left:40px;
  min-width: 200px;
}
        `],
        encapsulation: ViewEncapsulation.None
})

export class AppComponent {
    @ViewChild('EventLog') EventLogEle:any;
    public listData: Object =  [
  { text: "Hennessey Venom", id: "list-01" },
  { text: "Bugatti Chiron", id: "list-02" },
  { text: "Bugatti Veyron Super Sport", id: "list-03" },
  { text: "SSC Ultimate Aero", id: "list-04" },
  { text: "Koenigsegg CCR", id: "list-05" },
  { text: "McLaren F1", id: "list-06" },
  { text: "Aston Martin One- 77", id: "list-07" },
  { text: "Jaguar XJ220", id: "list-08" },
  { text: "McLaren P1", id: "list-09" },
  { text: "Ferrari LaFerrari", id: "list-10" }
];
   onclick(event){
    this.EventLogEle.nativeElement.innerHTML = "";
   }
   onSelect(args: SelectEventArgs){
    this.appendElement(args.text + "<b>&nbsp;&nbsp;is selected</b><hr>");
   }
   onActionBegin(){
     this.appendElement("<b>actionBegin </b> event is triggered<hr>");
   }
   onActionComplete(){
     this.appendElement("<b>actionComplete</b> is triggered <hr>");
   }
  appendElement(html: string): void {
     let span: HTMLElement = document.createElement("span");
     span.innerHTML = html;
     let log: HTMLElement = this.EventLogEle.nativeElement;
     log.insertBefore(span, log.firstChild);
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Load the spinner until list items are loaded

The features of the ListView component such as remote data-binding take more time to fetch data from corresponding dataSource/remote URL. In this case, you can use EJ2 Spinner to enhance the appearance of the UI. This section explains how to load a spinner component to groom the appearance.

Refer to the following code sample to render the spinner component.

    createSpinner({
        target: this.spinnerEle.nativeElement
    });
    showSpinner(this.spinnerEle.nativeElement);

Refer to the following code sample to render the ListView component.

let listviewInstance: ListView = new ListView({
    //Bind the DataManager instance to the dataSource property
    dataSource= new DataManager({
        url: '//js.syncfusion.com/ejServices/Wcf/Northwind.svc/',
        crossDomain: true
    }),

    //Bind the Query instance to the query property
    query= new Query().from('Products').select('ProductID,ProductName').take(10),

    //Map the appropriate columns to the fields property
    fields= { id: 'ProductID', text: 'ProductName' },

});

//Render the initialized ListView
listviewInstance.appendTo("#element");

Here, the data is fetched from Northwind Service URL; it takes a few seconds to load the data. To enhance the UI, the spinner component has been rendered initially. After the data is loaded from remote URL, the spinner component will be hidden in ListView actionComplete event.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild, ngAfterViewInit, ViewEncapsulation } from "@angular/core";
import { DataManager, Query, ODataV4Adaptor } from '@syncfusion/ej2-data';
import { createSpinner, showSpinner, setSpinner } from '@syncfusion/ej2-angular-popups';

@Component({
    selector: 'my-app',
    template: `
    <ejs-listview id='element' #list [dataSource]='dataSource' [width]='300' [query]='query' [fields]='fields' [showHeader]='true' [headerTitle]='headertitle' (actionComplete)='onActionComplete($event)' >
    </ejs-listview>
       <div #spinner id="spinner" ></div>
      `,
        styles: [`
        #element {
    display: block;
    max-width: 400px;
    min-height: 200px;
    margin: auto;
    border: 1px solid #dddddd;
    border-radius: 3px;
}
        `],
        encapsulation: ViewEncapsulation.None
})

export class AppComponent {
    @ViewChild('spinner') spinnerEle:any;
    public dataSource= new DataManager({
        url: 'http://js.syncfusion.com/ejServices/Wcf/Northwind.svc/',
        crossDomain: true
    }),
    public query = new Query().from('Products').select('ProductID,ProductName').take(10),
    public fields: Object = { id: 'ProductID', text: 'ProductName'  };
    public headertitle = 'Product Name';
    ngAfterViewInit(){
    createSpinner({
        target: this.spinnerEle.nativeElement;
    });
    showSpinner(this.spinnerEle.nativeElement);
   }
   onActionComplete(){
    this.spinnerEle.nativeElement.style.display = "none";
   }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Add and remove list items from the ListView component

You can add or remove list items from the ListView component using the addItem and removeItem methods. Refer to the following steps to add or remove a list item.

  • Render the ListView with data source, and use the template property to append the delete icon for each list item. Also, bind the click event for the delete icon using the actionComplete handler.

  • Render the Add Item button, and bind the click event. On the click event handler, pass data with random id to the addItem method to add a new list item on clicking the Add Item button.

  • Bind the click handler to the delete icon created in step 1. Within the click event, remove the list item by passing the delete icon list item to removeItem method.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<ejs-listview #list id='sample-list' [dataSource]='data' [fields]='fields' (actionComplete)='onComplete()'>
    <ng-template  #template let-data="">
    <div class='text-content'> {{data.text}} <span class = 'delete-icon'></span> </div>
    </ng-template>
    </ejs-listview>
    <button ejs-button id="btn" (click)="addItem()">Add Item</button>`,
})

export class AppComponent {
   @ViewChild('list')
   listviewInstance: ListViewComponent;
    //define the array of string
    public data: string[] =  [{ text: "Hennessey Venom", id: "1", icon: "delete-icon" },
  { text: "Bugatti Chiron", id: "2", icon: "delete-icon" },
  { text: "Bugatti Veyron Super Sport", id: "3", icon: "delete-icon" },
  { text: "Aston Martin One- 77", id: "4", icon: "delete-icon" },
  { text: "Jaguar XJ220", id: "list-5", icon: "delete-icon" },
  { text: "McLaren P1", id: "6", icon: "delete-icon" }];

public fields: Object = {text: "text", iconCss: "icon" };
deleteItem(args) {
  args.stopPropagation();
  let liItem = args.target.parentElement.parentElement;
  this.listviewInstance.removeItem(liItem);
  this.onComplete();
}
  onComplete() {
  let iconEle = document.getElementsByClassName("delete-icon");
  //Event handler to bind the click event for delete icon
  Array.from(iconEle).forEach((element) => {
    element.addEventListener("click", this.deleteItem.bind(this));
  });
}

addItem(){
  let data = {
    text: "Koenigsegg - " + (Math.random() * 1000).toFixed(0),
    id: (Math.random() * 1000).toFixed(0).toString(),
    icon: "delete-icon"
  };
  this.listviewInstance.addItem([data]);
}
}

{% endraw %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule, ButtonModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Customize dual list

The dual list contains two ListView. This allows you to move list items from one list to another using the client-side events. This section explains how to integrate the ListView component to achieve dual list.

Use cases

  • Stock exchanges of two different countries
  • Job applications (skill sets)

Integration of Dual List

Here, two ListView components have been used to display the list items. An ej2-button is used to transfer data between the ListView, and a textbox is used to achieve the UI of filtering support.

The dual list supports:

  • Moving whole data from one list to another.
  • Moving selected data from one list to another.
  • Filtering the list by using a client-side typed character.

In the ListView component, sorting is enabled using the sortOrder property, and the select event is triggered while selecting an item. Here, the select event is triggered to enable and disable button states.

Manipulating data

Moving whole data from the first list to the second list(>>)

  • Here, the whole data can be moved from the first ListView to the second by clicking the first button. When clicking the button, the whole list items are sliced, and concat with the second ListView. This button is enabled only when the data source of the first ListView is not empty.

Moving whole data from the second list to the first list(<<)

  • The functionality of the second button is the same as above, and data is transferred from the second list to the first list. This button is enabled only when the data source of the second ListView is not empty.

Moving selected item from one list to another list (>) and (<)

  • The Select event is triggered when selecting a list item in the ListView. The selected items can be transferred between two lists. These buttons will be enabled when selecting an item in lists.

Filtering method

  • The filtering method is used to filter list items when typing a character in the text box. In this method, the dataManager has been used to fetch data from the data source and display in ListView.

Sorting

  • By using the dual list, list items can be sorted in the ListView component using the sortOrder property. You can enable sorting in one ListView; in the same order, data can be transferred to another ListView.
Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild } from "@angular/core";
import { enableRipple } from "@syncfusion/ej2-base";
import { DataManager, Query, ODataV4Adaptor } from "@syncfusion/ej2-data";
enableRipple(true);

@Component({
    selector: 'my-app',
    template: `<div id="text1">
            <input #textbox class="e-input" type="text" id="firstInput" placeholder="Filter" title="Type in a name" (keyup)="onFirstKeyUp($event)" />
              </div>
            <ejs-listview #list1 id='list-1' [dataSource]='firstListData' [fields]='fields' [sortOrder]='Ascending'  (select)="onFirstListSelect()"></ejs-listview>
             <div id="btn">
             <button ejs-button #btn1 id="firstBtn" (click)="firstbtnclick()"> >> </button>
             <button ejs-button #btn2 id="secondBtn" [disabled]=true (click)="secondbtnclick()"> > </button>
             <button ejs-button #btn3 id="thirdBtn" [disabled]=true (click)="thirdbtnclick()"> < </button>
             <button ejs-button #btn4 id="fourthBtn" (click)="fourthbtnclick()"> << </button>
             </div>

            <div id="text2">
            <input #text class="e-input" type="text" id="secondInput" placeholder="Filter" title="Type in a name" (keyup)="onSecondKeyUp($event)" />
            </div>
            <ejs-listview #list2 id='list-2' [dataSource]='secondListData' [fields]='fields' [sortOrder]='Ascending' (select)="onSecondListSelect()"></ejs-listview>
        `,
})

export class AppComponent {
  public fields: Object;
  public firstListData, secondListData: any;
  constructor(){
   this.firstListData  = [
  { text: "Hennessey Venom", id: "list-01" },
  { text: "Bugatti Chiron", id: "list-02" },
  { text: "Bugatti Veyron Super Sport", id: "list-03" },
  { text: "SSC Ultimate Aero", id: "list-04" },
  { text: "Koenigsegg CCR", id: "list-05" },
  { text: "McLaren F1", id: "list-06" }
];

   this.secondListData = [
    { text: 'Aston Martin One- 77', id: 'list-07' },
    { text: 'Jaguar XJ220', id: 'list-08' },
    { text: 'McLaren P1', id: 'list-09' },
    { text: 'Ferrari LaFerrari', id: 'list-10' },
  ];

 this.fields = { text: "text", id: "id" };
  }
    @ViewChild('list1')firstListObj: ListViewComponent;
    @ViewChild('list2')secondListObj: ListViewComponent;
    @ViewChild('btn1')firstBtnObj: ButtonComponent;
    @ViewChild('btn2')secondBtnObj: ButtonComponent;
    @ViewChild('btn3')thirdBtnObj: ButtonComponent;
    @ViewChild('btn4')fourthBtnObj: ButtonComponent;
    @ViewChild('textbox')textboxEle: any;
    @ViewChild('text')textEle: any;
    ngAfterViewInit(){
        this.firstListData = this.firstListObj.dataSource.slice();
        this.secondListData = this.secondListObj.dataSource.slice();
    }
       //Here, all list items are moved to the second list on clicking move all button
    firstbtnclick() {
        this.secondListObj.dataSource = Array.prototype.concat.call(this.firstListObj.dataSource, this.secondListObj.dataSource);
        this.updateFirstListData();
        this.firstListObj.removeMultipleItems(this.firstListObj.liCollection);
        this.firstListData = this.firstListData.concat(this.firstListObj.dataSource);
        this.secondListData = this.secondListObj.dataSource.slice();
        this.firstBtnObj.disabled = true;
        this.onFirstKeyUp();
        this.setButtonState();
    }

    //Here, the selected list items are moved to the second list on clicking move button
  secondbtnclick() {
        let e = this.firstListObj.getSelectedItems();
        this.secondListObj.dataSource = Array.prototype.concat.call(this.secondListObj.dataSource, e.data);
        this.firstListObj.removeItem(e.item);
        this.firstListData = this.firstListObj.dataSource;
        this.secondListData = this.secondListObj.dataSource.slice();
        this.onFirstKeyUp();
        this.secondBtnObj.disabled = true;
        this.setButtonState();
    }

    //Here, the selected list items are moved to the first list on clicking move button
   thirdbtnclick () {
        let e = this.secondListObj.getSelectedItems();
        this.firstListObj.dataSource = Array.prototype.concat.call(this.firstListObj.dataSource, e.data);
        this.secondListObj.removeItem(e.item);
        this.secondListData = this.secondListObj.dataSource;
        this.firstListData = this.firstListObj.dataSource.slice();
        this.onSecondKeyUp();
        this.thirdBtnObj.disabled = true;
        this.setButtonState();

    }

    //Here, all list items are moved to the first list on clicking move all button
   fourthbtnclick() {
        this.firstListObj.dataSource = Array.prototype.concat.call(this.firstListObj.dataSource, this.secondListObj.dataSource);
        this.updateSecondListData();
        this.secondListObj.removeMultipleItems(this.secondListObj.liCollection);
        this.secondListData = this.secondListData.concat(this.secondListObj.dataSource);
        this.firstListData = this.firstListObj.dataSource.slice();
        this.onSecondKeyUp();
        this.setButtonState();

    }

    //Here, the ListView data source is updated to the first list
    updateFirstListData() {
        Array.prototype.forEach.call(this.firstListObj.liCollection, (list) => {
            this.firstListData.forEach((data, index) => {
                if (list.innerText.trim() === data.text) {
                    delete this.firstListData[index];
                }
            });
        });
        this.textboxEle.nativeElement.value= '';
        let ds = [];
        this.firstListData.forEach((data) => {
            ds.push(data);
        })
        this.firstListData = ds;

    }

    //Here, the ListView dataSource is updated for the second list
    updateSecondListData() {
        Array.prototype.forEach.call(this.secondListObj.liCollection, (list) => {
            this.secondListData.forEach((data, index) => {
                if (list.innerText.trim() === data.text) {
                    delete this.secondListData[index];
                }
            });

        });
        this.textEle.nativeElement.value = '';
        let ds = [];
        this.secondListData.forEach((data) => {
            ds.push(data);
        })
        this.secondListData = ds;

    }
    onFirstListSelect() {
        this.secondBtnObj.disabled = false;
    }
    onSecondListSelect() {
        this.thirdBtnObj.disabled = false;
    }

    //Here, filtering is handled using the dataManager for the first list
    onFirstKeyUp(e) {
        let value = this.textboxEle.nativeElement.value;
        let data = new DataManager(this.firstListData).executeLocal(new Query().where('text', 'startswith', value, true));
        if (!value) {
            this.firstListObj.dataSource = this.firstListData.slice();
        } else {
            this.firstListObj.dataSource = data;
        }
    }
    //Here, filtering is handled using the dataManager for the second list
     onSecondKeyUp(e) {
        let value =this.textEle.nativeElement.value;
        let data = new DataManager(this.secondListData).executeLocal(new Query().where('text', 'startswith', value, true));
        if (!value) {
            this.secondListObj.dataSource = this.secondListData.slice();
        } else {
            this.secondListObj.dataSource = data;
        }
    }

    //Here, the state of the button is changed
    setButtonState() {
        if (this.firstListObj.dataSource.length) {
            this.firstBtnObj.disabled = false;
        } else {
            this.firstBtnObj.disabled = true;
            this.secondBtnObj.disabled = true;
        }

        if (this.secondListObj.dataSource.length) {
            this.fourthBtnObj.disabled = false;
        } else {
            this.fourthBtnObj.disabled = true;
            this.thirdBtnObj.disabled = true;
        }

    }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule, ButtonModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Hide checkbox in listview

The checkbox of the any list item can be hidden by using htmlAttributes of fields object. With the help of htmlAttributes we can add unique class to each list item that will be rendered from the data source, from the CSS class we can hide the checkbox of the list item.

In this sample, we had hidden the multiple leaf node of nested list. The e-checkbox-hidden class has been added in the data source where the checkbox needs to be hidden. Refer the below snippet for simple data source.

    {
        'text': 'New York',
        'id': '3002',
        'category': 'USA',
        'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' }
    }

Even though we have hidden the checkbox the functionality will be same for the list item which might affect the getSelectedItems method. So, to counteract that we will follow certain logic in the select event. The Logic here is to remove the e-active class from the other checkbox hidden list item which will be added when we select on that item and retain e-active on currently selected item.

In this process we will exclude the visible checkbox list items and only consider the hidden checkbox items.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild } from "@angular/core";

@Component({
    selector: 'my-app',
    template: `
    <div id="sample">
      <ejs-listview #list id='folderCheckbox' [dataSource]='dataSource' [fields]='fields' [sortOrder]='Ascending' headerTitle='Mixed Leaf Checkbox Hidden List' [showHeader]=true [showCheckBox]=true (select)="onSelect($event)"></ejs-listview>
    </div>
    `,
})

export class AppComponent {

  public dataSource: Object = [
    {
        'text': 'Asia',
        'id': '01',
        'category': 'Continent',

        'child': [{
            'text': 'India',
            'id': '1',
            'category': 'Asia',

            'child': [{
                'text': 'Delhi',
                'id': '1001',
                'category': 'India',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Kashmir',
                'id': '1002',
                'category': 'India',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Goa',
                'id': '1003',
                'category': 'India',
                'htmlAttributes': { 'class': 'e-file' },
            },
            ]
        },
        {
            'text': 'China',
            'id': '2',
            'category': 'Asia',

            'child': [{
                'text': 'Zhejiang',
                'id': '2001',
                'category': 'China',
                'htmlAttributes': { 'class': 'e-file' },
            },
            {
                'text': 'Hunan',
                'id': '2002',
                'category': 'China',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Shandong',
                'id': '2003',
                'category': 'China',
                'htmlAttributes': { 'class': 'e-file' },
            }]
        }]
    },

    {
        'text': 'North America',
        'id': '02',
        'category': 'Continent',

        'child': [{
            'text': 'USA',
            'id': '3',
            'category': 'North America',

            'child': [{
                'text': 'California',
                'id': '3001',
                'category': 'USA',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'New York',
                'id': '3002',
                'category': 'USA',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Florida',
                'id': '3003',
                'category': 'USA',
                'htmlAttributes': { 'class': 'e-file' },
            }]
        },
        {
            'text': 'Canada',
            'id': '4',
            'category': 'North America',

            'child': [{
                'text': 'Ontario',
                'id': '4001',
                'category': 'Canada',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Alberta',
                'id': '4002',
                'category': 'Canada',
                'htmlAttributes': { 'class': 'e-file' },
            },
            {
                'text': 'Manitoba',
                'id': '4003',
                'category': 'Canada',
                'htmlAttributes': { 'class': 'e-file' },
            }]
        }]
    },

    {
        'text': 'Europe',
        'id': '03',
        'category': 'Continent',

        'child': [{
            'text': 'Germany',
            'id': '5',
            'category': 'Europe',

            'child': [{
                'text': 'Berlin',
                'id': '5001',
                'category': 'Germany',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Bavaria',
                'id': '5002',
                'category': 'Germany',
                'htmlAttributes': { 'class': 'e-file' },
            },
            {
                'text': 'Hesse',
                'id': '5003',
                'category': 'Germany',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            }]
        }, {
            'text': 'France',
            'id': '6',
            'category': 'Europe',

            'child': [{
                'text': 'Paris',
                'id': '6001',
                'category': 'France',
                'htmlAttributes': { 'class': 'e-file' },
            },
            {
                'text': 'Lyon',
                'id': '6002',
                'category': 'France',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Marseille',
                'id': '6003',
                'category': 'France',
                'htmlAttributes': { 'class': 'e-file' },
            }]
        }]
    },
    {
        'text': 'Australia',
        'id': '04',
        'category': 'Continent',

        'child': [{
            'text': 'Australia',
            'id': '7',
            'category': 'Australia',

            'child': [{
                'text': 'Sydney',
                'id': '7001',
                'category': 'Australia',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Melbourne',
                'id': '7002',
                'category': 'Australia',
                'htmlAttributes': { 'class': 'e-file' },
            },
            {
                'text': 'Brisbane',
                'id': '7003',
                'category': 'Australia',
                'htmlAttributes': { 'class': 'e-file' },
            }]
        }, {
            'text': 'New Zealand',
            'id': '8',
            'category': 'Australia',

            'child': [{
                'text': 'Milford Sound',
                'id': '8001',
                'category': 'New Zealand',
                'htmlAttributes': { 'class': 'e-file' },
            },
            {
                'text': 'Tongariro National Park',
                'id': '8002',
                'category': 'New Zealand',
                'htmlAttributes': { 'class': 'e-file' },
            },
            {
                'text': 'Fiordland National Park',
                'id': '8003',
                'category': 'New Zealand',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            }]
        }]
    },
    {
        'text': 'Africa',
        'id': '05',
        'category': 'Continent',

        'child': [{
            'text': 'Morocco',
            'id': '9',
            'category': 'Africa',

            'child': [{
                'text': 'Rabat',
                'id': '9001',
                'category': 'Morocco',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Toubkal',
                'id': '9002',
                'category': 'Morocco',
                'htmlAttributes': { 'class': 'e-file' },
            },
            {
                'text': 'Todgha Gorge',
                'id': '9003',
                'category': 'Morocco',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            }]
        }, {
            'text': 'South Africa',
            'id': '10',
            'category': 'Africa',

            'child': [{
                'text': 'Cape Town',
                'id': '10001',
                'category': 'South Africa',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Pretoria',
                'id': '10002',
                'category': 'South Africa',
                'htmlAttributes': { 'class': 'e-file e-checkbox-hidden' },
            },
            {
                'text': 'Bloemfontein',
                'id': '10003',
                'category': 'South Africa',
                'htmlAttributes': { 'class': 'e-file' },
            }]
        }]
    }
];
    public fields = { tooltip: 'text' };
    @ViewChild('list')listviewInstance: ListViewComponent;
    onSelect(args){
       let normalElements: HTMLElement[] = Array.prototype.slice.call((this.listviewInstance as any).curUL.getElementsByClassName('e-checkbox-hidden'));

        // Looping through all the selected element and removing e-active class
        // to avoid behaviour interference  with getSelectedItems method
        normalElements.forEach((element) => {
            element.classList.remove('e-active');
        });

        // Finally adding e-active class to currently selected item except checkbox item.
        // because if it is checkbox item their actions will taken care from the source side itself.
        if (args.item.classList.contains('e-checkbox-hidden')) {
            args.item.classList.add('e-active');
        }
   }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';

/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Customize ListView with dynamic tags

You can customize the ListView items using the template property. Here, the dynamic tags are added and removed in the list item from another ListView. Refer to the following steps to achieve this.

  • Initialize dynamic ListView with required property that holds the tags of parent ListView, and bind the select event (triggers when the list item is selected), in which you can get and add the selected item value as tags into parent ListView. Refer to the following code sample.
//Select the event that is is rendered inside dialog for ListView
addTag(e) {
    let listTag = document.createElement('span');
    listTag.className = 'advanced-option';
    let labelElem = document.createElement('span');
    labelElem.className = 'label';
    let deleteElem = document.createElement('span');
    deleteElem.className = 'delete';
    deleteElem.onclick = this.removeTag;
    labelElem.innerHTML = e.text;
    listTag.appendChild(labelElem);
    listTag.appendChild(deleteElem);
    let tag = document.createElement('span');
    tag.className = 'advanced-option-list';
    tag.appendChild(listTag);
    this.listviewInstance.element.querySelector('.e-active').appendChild(tag);
}
  • Render the dialog component with empty content and append the created dynamic ListView object to the dialog on created event.

  • Bind the click event for button icon (+) to update the ListView data source with tags, and open the dialog with this dynamic ListView. Refer to the following code sample.

//Method to hide/show the dialog and update the ListView data source
renderDialog(id) {
    if (document.getElementsByClassName('e-popup-open').length != 0) {
        this.dialog.hide();
    }
    else {
        this.listObj.dataSource = this.datasource[id];
        this.listObj.dataBind();
        this.dialog.show();
    }

}
  • Bind the click event with added dynamic tags to remove it. Refer to the following code sample.
//Method to remove the list item
removeTag() {
    this.parentNode.parentNode.remove();
}
Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `<div id="sample">
    <ejs-listview #list id='templatelist' [dataSource]='data' [fields]='fields' width=350 >
    <ng-template  #template let-data="">
    <div><span class="templatetext">{{data.Name}} </span> <span class="designationstyle"><button ejs-button id="{{data.Id}}" class="e-but" iconCss='e-icons e-add-icon' cssClass='e-small e-round' (click)='onClick($event)'></button></span></div>
    </ng-template>
    </ejs-listview>
   <ejs-dialog id='dialog' #ejDialog width='200px' [animationSettings]='animation' [visible]='false' showCloseIcon='true' [position]='position'>
      <ng-template #content>
        <ejs-listview #List id="list" showHeader=true headerTitle='Favorite' width='200px' [dataSource]='datasource.Brooke' [fields]='fields' (select)='addTag($event)'></ejs-listview>
      </ng-template>
      </ejs-dialog>
    </div>`
})

export class AppComponent {
    @ViewChild('list') listviewInstance: ListViewComponent;
    @ViewChild('List') listObj: ListViewComponent;
    @ViewChild('ejDialog') dialog: DialogComponent;
    //define the array of string
public data: string[] =  [{ "Id": "Brooke", "Name": "Brooke" },
{ "Id": "Claire", "Name": "Claire" },
{ "Id": "Erik", "Name": "Erik" },
{ "Id": "Grace", "Name": "Grace" },
{ "Id": "Jacob", "Name": "Jacob" }];

public fields: Object = {text: "Name"};
public position: Object;
public animation: Object = {effect: 'None'};

public brookeTag : Object = [{ "id": "list11", "Name": "Discover Music" },
{ "id": "list12", "Name": "Sales and Events" },
{ "id": "list13", "Name": "Categories" },
{ "id": "list14", "Name": "MP3 Albums" },
{ "id": "list15", "Name": "More in Music" },
];

public claireTag : Object = [{ "id": "list21", "Name": "Songs" },
{ "id": "list22", "Name": "Bestselling Albums" },
{ "id": "list23", "Name": "New Releases" },
{ "id": "list24", "Name": "Bestselling Songs" },
];

public erikTag : Object = [{ "id": "list31", "Name": "Artwork" },
{ "id": "list32", "Name": "Abstract" },
{ "id": "list33", "Name": "Acrylic Mediums" },
{ "id": "list34", "Name": "Creative Acrylic" },
{ "id": "list35", "Name": "Canvas Art" }
];

public graceTag : Object = [{ "id": "list41", "Name": "Rock" },
{ "id": "list42", "Name": "Gospel" },
{ "id": "list43", "Name": "Latin Music" },
{ "id": "list44", "Name": "Jazz" },
];

public jacobTag: Object = [{ "id": "list51", "Name": "100 Albums - $5 Each" },
{ "id": "list52", "Name": "Hip-Hop and R&B Sale" },
{ "id": "list53", "Name": "CD Deals" }
];

public datasource: any = { "Brooke": this.brookeTag, "Claire": this.claireTag, "Erik": this.erikTag, "Grace": this.graceTag, "Jacob": this.jacobTag };

ngAfterViewChecked(){
setTimeout(()=>{
  this.position =  { X: document.querySelector('.e-add-icon').getBoundingClientRect().left + 50, Y: document.querySelector('.e-add-icon').getBoundingClientRect().top - 5 };
},1000);
}
onClick(e){
  this.renderDialog(e.currentTarget.id);
}
renderDialog(id) {
    if (document.getElementsByClassName('e-popup-open').length != 0) {
        this.dialog.hide();
    }
    else {
        this.listObj.dataSource = this.datasource[id];
        this.listObj.dataBind();
        this.dialog.show();
    }

}
addTag(e) {
    let listTag = document.createElement('span');
    listTag.className = 'advanced-option';
    let labelElem = document.createElement('span');
    labelElem.className = 'label';
    let deleteElem = document.createElement('span');
    deleteElem.className = 'delete';
    deleteElem.onclick = this.removeTag;
    labelElem.innerHTML = e.text;
    listTag.appendChild(labelElem);
    listTag.appendChild(deleteElem);
    let tag = document.createElement('span');
    tag.className = 'advanced-option-list';
    tag.appendChild(listTag);
    this.listviewInstance.element.querySelector('.e-active').appendChild(tag);
}
removeTag() {
    this.parentNode.parentNode.remove();
}
}


{% endraw %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { DialogComponent } from '@syncfusion/ej2-angular-popups';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule, ButtonModule
    ],
    declarations: [AppComponent,DialogComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

ListView manipulation in grid layout

In Listview, list items can be rendered in grid layout with following data manipulations.

  • Add Item

  • Remove Item

  • Sort Items

  • Filter Items

Grid Layout

In this section, we will discuss about rendering of list items in grid layout.

  • Initialize and render ListView with dataSource which will render list items in list layout.

  • Now, add the below CSS to list item. This will make list items to render in grid layout

#element .e-list-item {
        height: 100px;
        width: 100px;
        float: left;
}

In the below sample, we have rendered List items in grid layout.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
          <ejs-listview id='element' [dataSource]='data'>
          <ng-template #template let-data="">
          <img id="listImage" src="./apple.png" alt="apple" />
          </ng-template>
          </ejs-listview>
        `,
  })

export class AppComponent {
  public data = [1, 2, 3, 4, 5, 6, 7, 8, 9];
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Data manipulation

In this section, we will discuss about ListView data manipulations.

Add Item

We can add list item using addItem API. This will accept array of data as argument.

 this.$refs.listViewInstance.addItem([{text: 'Apricot', id: '32'}]);

In the below sample, you can add new fruit item by clicking add button which will open dialog box with fruit name and image URL text box. After entering the item details, click the add button. This will add your new fruit item.

Remove item

We can remove list item using removeItem API. This will accept fields with id or list item element as argument.

 this.$refs.listViewInstance.removeItem({id: '32'});

In the below sample, you can remove fruit by hovering the fruit item which will show delete button and click that delete button to delete that fruit from your list.

Sort Items

Listview can be sorted either in Ascending or Descending order. To enable sorting in your ListView, set sortOrder as Ascending or Descending.

<ejs-listview sortOrder='Ascending'></ejs-listview>

We can also set sorting after component initialization.

this.listViewInstance.sortOrder = 'Ascending'

In the below sample, we have sorted fruits in Ascending order. To sort it in descending, click on sort order icon and vice versa.

Filter Items

Listview data can be filtered with the help of dataManager. After filtering the data, update ListView dataSource with filtered data.

let value = this.textboxEle.nativeElement.value;  //input text box value
let filteredData = new DataManager(this.listdata).executeLocal(
        new Query().where("text", "startswith", value, true)
);

listViewInstance.dataSource = filteredData;

In the below sample, we can filter fruit items with the help of search text box. This will filter fruit items based on your input. Here we used startswith of input text to filter data in DataManager.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild, ElementRef } from '@angular/core';
import { closest, enableRipple } from '@syncfusion/ej2-base';
import { DataManager, Query } from "@syncfusion/ej2-data";
enableRipple(true);

@Component({
    selector: 'my-app',
    template: `
          <div id="sample">
        <div class="headerContainer">
            <div class="e-input-group">
                <input id="search" #searchEle class="e-input" type="text" placeholder="Search fruits" (keyup)='onKeyUp($event)'/>
                <span class="e-input-group-icon e-input-search"></span>
            </div>
            <button ejs-button id="sort" class="e-control e-btn e-small e-round e-primary e-icon-btn" (click)='sortItems($event)' title="Sort fruits" data-ripple="true">
                <span class="e-btn-icon e-icons e-sort-icon-ascending"></span>
            </button>
            <button ejs-button id="add" class="e-control e-btn e-small e-round e-primary e-icon-btn" (click)='addItem($event)' title="Add fruit" data-ripple="true">
                <span class="e-btn-icon e-icons e-add-icon"></span>
            </button>
            <ejs-dialog id="dialog" #dialogObj width='300px' [visible]='false' header='Add Fruit' showCloseIcon='true' [buttons]='addButtons'>
            <ng-template #content let-data="">
            <div id="listDialog"><div class="input_name"><label for="name">Fruit Name: </label><input id="name" class="e-input" type="text" placeholder="Enter fruit name"/></div><div><label for="imgurl">Fruit Image: </label><input id="imgurl" class="e-input" type="text" placeholder="Enter image url"/></div></div>
            </ng-template>
            </ejs-dialog>
        </div>
            <ejs-listview id='element' #listview [dataSource]='fruitsdata' sortOrder='Ascending' (actionComplete)='wireEvents()'>
            <ng-template #template let-data="">
            <div class="fruits"><div class="first"><img id="listImage" src={{data.imgUrl}} alt="fruit" /><button ejs-button class="delete e-control e-btn e-small e-round e-delete-btn e-primary e-icon-btn" data-ripple="true"><span class="e-btn-icon e-icons delete-icon"></span></button></div><div class="fruitName">{{data.text}}</div></div>
            </ng-template>
            </ejs-listview>
    </div>
        `,
  })

export class AppComponent {
  @ViewChild('listview') listViewInstance: any;
  @ViewChild('dialogObj')dialogObj: any;
  @ViewChild('searchEle')searchEle: any;
  public  fruitsdata = [
    { text: 'Date', id: '1', imgUrl: './dates.jpg' },
    { text: 'Fig', id: '2', imgUrl: './fig.jpg' },
    { text: 'Apple', id: '3', imgUrl: './apple.png' },
    { text: 'Apricot', id: '4', imgUrl: './apricot.jpg' },
    { text: 'Grape', id: '5', imgUrl: './grape.jpg' },
    { text: 'Strawberry', id: '6', imgUrl: './strawberry.jpg' },
    { text: 'Pineapple', id: '7', imgUrl: './pineapple.jpg' },
    { text: 'Melon', id: '8', imgUrl: './melon.jpg' },
    { text: 'Lemon', id: '9', imgUrl: './lemon.jpg' },
    { text: 'Cherry', id: '10', imgUrl: './cherry.jpg' },
];
public addButtons= [{
        click: this.dlgButtonClick.bind(this), buttonModel: { content: 'Add', isPrimary: true }
    }];
 wireEvents() {
    Array.prototype.forEach.call(document.getElementsByClassName('e-delete-btn'), (ele) => {
        ele.addEventListener('click', this.onDeleteBtnClick.bind(this));
    });
    },
addItem() {
    (document.getElementById("name")).value = "";
    (document.getElementById("imgurl")).value = "";
    this.dialogObj.show();
},
sortItems() {
    let ele = document.getElementById("sort").firstElementChild;
    let des = ele.classList.contains('e-sort-icon-descending') ? true : false;
    if (des) {
        ele.classList.remove('e-sort-icon-descending');
        ele.classList.add('e-sort-icon-ascending');
        this.listViewInstance.sortOrder = 'Ascending';
    } else {
        ele.classList.remove('e-sort-icon-ascending');
        ele.classList.add('e-sort-icon-descending');
        this.listViewInstance.sortOrder = 'Descending'
    }
    this.listViewInstance.dataBind();
    this.wireEvents();
},
onKeyUp(e) {
    let value = this.searchEle.nativeElement.value;
    let data = new DataManager(this.fruitsdata).executeLocal(
        new Query().where("text", "startswith", value, true)
    );
    if (!value) {
        this.listViewInstance.dataSource = this.fruitsdata.slice();
    } else {
        this.listViewInstance.dataSource = data;
        this.listViewInstance.dataBind();
    }
},
onDeleteBtnClick(e) {
    e.stopPropagation();
    let li = closest(e.currentTarget, '.e-list-item');
    let data = this.listViewInstance.findItem(li);
    this.listViewInstance.removeItem(data);
    new DataManager(this.fruitsdata).remove('id', { id: data.id });
},
 dlgButtonClick() {
    let name = (document.getElementById("name")).value;
    let url = (document.getElementById("imgurl")).value;
    let id = Math.random() * 10000;
    this.listViewInstance.addItem([{ text: name, id: id, imgUrl: url }]);
    this.fruitsdata.push({ text: name, id: id, imgUrl: url });
    this.listViewInstance.element.querySelector('[data-uid="'+ id + '"]').getElementsByClassName('e-delete-btn')[0].addEventListener('click', this.onDeleteBtnClick.bind(this));
    this.dialogObj.hide();
}
}


{% endraw %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
import { DialogComponent } from '@syncfusion/ej2-angular-popups';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent,DialogComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

We can use anchor tag along with href attribute in our ListView template property for navigation.

{% raw %}

<ng-template #template let-data="">
   <a target='_blank' href="{{data.url}}">{{data.name}}</a>
</ng-template>

{% endraw %}

In the below sample, we have rendered ListView with search engines URL.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
          <div id="sample">
    <ejs-listview id='List' [dataSource]='data' headerTitle='Search engines' showHeader='true'>
    <ng-template #template let-data="">
   <a target='_blank' href="{{data.url}}">{{data.name}}</a>
    </ng-template>
    </ejs-listview>
  </div>
        `,
  })

export class AppComponent {

  public data=[
        {name: 'Google', url: 'https://www.google.com'},
        {name: 'Bing', url: 'https://www.bing.com' },
        {name: 'Yahoo', url: 'https://www.yahoo.com'},
        {name: 'Ask.com', url: 'https://www.ask.com'},
        {name: 'AOL.com', url: 'https://www.aol.com'},
    ];

}


{% endraw %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Load HTML content via AJAX

We can set external HTML page content as template for our ListView component by making use of AJAX call.

let ajax = new Ajax('./template.html', 'GET', false);
    ajax.onSuccess = (e)=>{
        this.listtemplate = e;
    };
    ajax.send();

In the below sample, we have rendered smartphone settings template from external HTML file.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild } from '@angular/core';
import { Ajax } from '@syncfusion/ej2-base';

@Component({
    selector: 'my-app',
    template: `
          <ejs-listview id='List' [dataSource]='data' showHeader='true' headerTitle='Settings' [template]="listtemplate">
        </ejs-listview>
        `
        ]
})

export class AppComponent {
  public listtemplate;
  public data =  [
    { name: 'Network & Internet', id: '0', description: 'Wi-Fi, mobile, data usage, hotspot' },
    { name: 'Connected devices', id: '1', description: 'Bluetooth, cast, NFC' },
    { name: 'Battery', id: '2', description: '18% -4h 12m left' },
    { name: 'Display', id: '3', description: 'Wallpaper, sleep, font size' },
    { name: 'Sound', id: '4', description: 'Volume, vibration, Do Not Disturb' },
    { name: 'Storage', id: '5', description: '52% used - 15.48 GB free' }
    ];
    ngOnInit(){
        let ajax = new Ajax('./template.html', 'GET', false);
        ajax.onSuccess = (e)=>{
          this.listtemplate = e;
        };
        ajax.send();
    }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

ListView with Drag and Drop feature (Reorder)

In ListView component, we don’t have drag and drop support. But we can achieve this requirement using TreeView component with ListView appearance.

Drag and Drop in TreeView component was enabled by setting allowDragAndDrop to true.

<ejs-treeview id='element' [fields]='fields' allowDragAndDrop='true'></ejs-treeview>

The TreeView component is used to represent hierarchical data in a tree like structure. So, list items in TreeView can be dropped to child of target element. we can prevent this behaviour by cancelling the nodeDragStop and nodeDragging events.

<ejs-treeview id='element' [fields]='fields' allowDragAndDrop='true' (nodeDragging)='onDragStop($event)' (nodeDragStop)='onDragStop($event)'></ejs-treeview>

fields= { dataSource: this.data, id: 'id', text: 'text' },

onDragStop(args) {
    //Block the Child Drop operation in TreeView
   let  draggingItem = document.getElementsByClassName("e-drop-in");
    if (draggingItem.length == 1) {
        draggingItem[0].classList.add('e-no-drop');
        args.cancel = true;
    }
}

In the below sample, we have rendered draggable list items.

Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
          <div id="sample">
    <ejs-treeview id='element' [fields]='fields' allowDragAndDrop='true' (nodeDragging)='onDragStop($event)' (nodeDragStop)='onDragStop($event)'></ejs-treeview>
   </div>
        `,
  })

export class AppComponent {

  public data=[
    { text: 'Hennessey Venom', id: 'list-01' },
    { text: 'Bugatti Chiron', id: 'list-02' },
    { text: 'Bugatti Veyron Super Sport', id: 'list-03' },
    { text: 'SSC Ultimate Aero', id: 'list-04' },
    { text: 'Koenigsegg CCR', id: 'list-05' },
    { text: 'McLaren F1', id: 'list-06' },
    { text: 'Aston Martin One- 77', id: 'list-07' },
    { text: 'Jaguar XJ220', id: 'list-08' },
    { text: 'McLaren P1', id: 'list-09' },
    { text: 'Ferrari LaFerrari', id: 'list-10' },
];

public fields = { dataSource: this.data, id: 'id', text: 'text' };

onDragStop(args) {
    //Block the Child Drop operation in TreeView
    let draggingItem = document.getElementsByClassName("e-drop-in");
    if (draggingItem.length == 1) {
        draggingItem[0].classList.add('e-no-drop');
        args.cancel = true;
    }
}
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { TreeViewModule } from '@syncfusion/ej2-angular-navigations';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        TreeViewModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Customize ListView as Chat Window

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.

{% raw %}

        <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">{{data.text}}</div>
                    <div id="info">{{data.contact}}</div>
                </div>
                <div id="image" *ngIf="data.avatar!=''"><span class="e-avatar img1 e-avatar-circle">{{data.avatar}}</span></div>
                <div id="image" *ngIf="data.avatar==''"><span class="{{data.pic}} 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">{{data.avatar}}</span></div>
                <div id="image2" *ngIf="data.avatar==''"><span class="{{data.pic}} img2 e-avatar e-avatar-circle"> </span></div>
                <div id="content1">
                    <div class="name1">{{data.text}}</div>
                    <div id="info1">{{data.contact}}</div>
                </div>
            </ng-template>
        </ng-template>

{% endraw %}

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](https://ej2.syncfusion.com/documentation/angular/list-view/api-listView.html#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 = "";
}
Source
Preview
app.component.ts
app.module.ts
main.ts
import { Component, ViewChild } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
    <ejs-listview id='List' #list [dataSource]='data' headerTitle="Chat" showHeader="true" width="350px" [fields]='fields'>
        <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">{{data.text}}</div>
                    <div id="info">{{data.contact}}</div>
                </div>
                <div id="image" *ngIf="data.avatar!=''"><span class="e-avatar img1 e-avatar-circle">{{data.avatar}}</span></div>
                <div id="image" *ngIf="data.avatar==''"><span class="{{data.pic}} 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">{{data.avatar}}</span></div>
                <div id="image2" *ngIf="data.avatar==''"><span class="{{data.pic}} img2 e-avatar e-avatar-circle"> </span></div>
                <div id="content1">
                    <div class="name1">{{data.text}}</div>
                    <div id="info1">{{data.contact}}</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 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 = "";
  }
}


{% endraw %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ListViewModule } from '@syncfusion/ej2-angular-lists';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        ListViewModule, ButtonModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);