NativeScript Angular

Listview

Using a ListView control inside Angular app requires some special attention due to the complexity of the NativeScript ListView control, with custom item templates, bindings and so on.

The NativeScript-angular plugin provides a custom Angular component which simplifies the way native ListView is used.

Note: Using the ListView component inside a ScrollView or ScrollView inside the ListView's items can lead to a poor user interface performance and can reflect the user experience. For avoiding those issues, we should specify the height explicitly for the ListView in the scenario when the ListView is nested in ScrollView and the ScrollView's height - when the component is used inside the ListView. Example 1 (ListView in ScrollView):

<ScrollView>
    <StackLayout>
        <ListView height="150" [items]="countries">
            <ng-template let-country="item" let-i="index" let-odd="odd" let-even="even">
                <!-- ....... -->
            </ng-template>
        </ListView>
    </StackLayout>
</ScrollView>

Example 2 (ScrollView in ListView):

<ListView [items]="countries">
    <ng-template let-country="item" let-i="index" let-odd="odd" let-even="even">
        <StackLayout>
            <ScrollView height="150" >
                <!-- ....... -->
            </ScrollView>
        </StackLayout>
    </ng-template>
</ListView>

Image

Usage

<ListView [items]="items" (itemTap)="onItemTap($event)" class="list-group">
    <ng-template let-item="item" let-i="index" let-odd="odd" let-even="even">
        <!-- The item template can only have a single root view container (e.g. GridLayout, StackLayout, etc.)-->
        <GridLayout>
            <Label [text]="item.name" class="list-group-item"></Label>
        </GridLayout>
    </ng-template>
</ListView>
import { Component, OnInit } from "@angular/core";
import { ItemService, Item } from "./usage.service";
import { ItemEventData } from "tns-core-modules/ui/list-view";

@Component({
    moduleId: module.id,
    templateUrl: "./usage.component.html"
})
export class ListViewUsageComponent implements OnInit {
    items: Array<Item>;

    constructor(private _itemService: ItemService) { }

    ngOnInit(): void {
        this.items = this._itemService.getItems();
    }

    onItemTap(args: ItemEventData) {
        console.log(`Index: ${args.index}; View: ${args.view} ; Item: ${this.items[args.index]}`);
    }
}
import { Injectable } from "@angular/core";
import { ListViewExamplesModule } from "../listview-examples.module";

@Injectable({
    providedIn: "root"
})
export class ItemService {
    private items = new Array<Item>(
        { id: 1, name: "Ter Stegen", role: "Goalkeeper" },
        { id: 3, name: "Piqué", role: "Defender" },
        { id: 4, name: "I. Rakitic", role: "Midfielder" },
        { id: 5, name: "Sergio", role: "Midfielder" },
        { id: 6, name: "Denis Suárez", role: "Midfielder" },
        { id: 7, name: "Arda", role: "Midfielder" },
        { id: 8, name: "A. Iniesta", role: "Midfielder" },
        { id: 9, name: "Suárez", role: "Forward" },
        { id: 10, name: "Messi", role: "Forward" },
        { id: 11, name: "Neymar", role: "Forward" },
        { id: 12, name: "Rafinha", role: "Midfielder" },
        { id: 13, name: "Cillessen", role: "Goalkeeper" },
        { id: 14, name: "Mascherano", role: "Defender" },
        { id: 17, name: "Paco Alcácer", role: "Forward" },
        { id: 18, name: "Jordi Alba", role: "Defender" },
        { id: 19, name: "Digne", role: "Defender" },
        { id: 20, name: "Sergi Roberto", role: "Midfielder" },
        { id: 21, name: "André Gomes", role: "Midfielder" },
        { id: 22, name: "Aleix Vidal", role: "Midfielder" },
        { id: 23, name: "Umtiti", role: "Defender" },
        { id: 24, name: "Mathieu", role: "Defender" },
        { id: 25, name: "Masip", role: "Goalkeeper" }
    );

    getItems(): Array<Item> {
        return this.items;
    }

    getItem(id: number): Item {
        return this.items.filter((item) => item.id === id)[0];
    }
}

export class Item {
    constructor(public id: number, public name: string, public role: string) { }
}

Improve this document

Demo Source


Styling

The ListView supports the common CSS styling (e.g., padding, margin, background-color, etc.). Additionally, you can use separatorColor, rowHeight and iosEstimatedRowHeight to further customize the ListView's styles.

<!-- 
    The @nativescript/theme provides ListView CSS classes (`list-group` & `list-group-item`) for setting recommended paddings & margins for ListView items.
    These class names adds a bit of spacing and the theme’s color scheme. 
-->
<ListView [items]="items" class="list-group" 
          backgroundColor="red" separatorColor="blue">
    <ng-template let-item="item">
        <GridLayout height="60">
            <Label [text]="item.name" class="list-group-item" color="white"></Label>
        </GridLayout>
    </ng-template>
</ListView>

Improve this document

Demo Source


Tips And Tricks

Item Templates

Use itemTemplateSelector property to create multiple item templates. The itemTemplateSelector accepts a function that returns a value for nsTemplateKey.

<ListView [items]="items" class="list-group" [itemTemplateSelector]="templateSelector" row="0">
    <ng-template nsTemplateKey="red" let-item="item" let-i="index">
        <GridLayout>
            <Label [text]="item.name" backgroundColor="red" color="white"></Label>
        </GridLayout>
    </ng-template>

    <ng-template nsTemplateKey="green" let-item="item" let-i="index">
        <GridLayout>
            <Label [text]="item.name" backgroundColor="green" color="yellow"></Label>
        </GridLayout>
    </ng-template>
</ListView> 
import { Component, Input, OnChanges, SimpleChanges, OnInit } from "@angular/core";
import { ItemService, Item } from "../usage/usage.service";
import { ItemEventData } from "tns-core-modules/ui/list-view";

@Component({
    moduleId: module.id,
    templateUrl: "./tips-and-tricks.component.html"
})
export class ListViewTipsComponent implements OnInit {
    items: Array<Item>;

    constructor(private _itemService: ItemService) { }

    ngOnInit(): void {
        this.items = this._itemService.getItems();
    }

    onItemTap(args: ItemEventData) {
        console.log(`Index: ${args.index}; View: ${args.view} ; Name: ${this.items[args.index].name}`);
    }

    templateSelector(item: Item, index: number, items: any) {
        return index % 2 === 0 ? "red" : "green";
    }
}

Custom Component Template

Common scenario in Angular is to reuse given component via its selector name (e.g., sdk-child-component). The below scenario demonstrates how to pass data from the parent ListView to its children components (which are used as template).

<ListView [items]="items" class="list-group" [itemTemplateSelector]="templateSelector" row="0">
    <ng-template nsTemplateKey="red" let-item="item" let-i="index">
        <GridLayout>
            <Label [text]="item.name" backgroundColor="red" color="white"></Label>
        </GridLayout>
    </ng-template>

    <ng-template nsTemplateKey="green" let-item="item" let-i="index">
        <GridLayout>
            <Label [text]="item.name" backgroundColor="green" color="yellow"></Label>
        </GridLayout>
    </ng-template>
</ListView> 
import { Component, Input, OnChanges, SimpleChanges, OnInit } from "@angular/core";
import { ItemService, Item } from "../usage/usage.service";
import { ItemEventData } from "tns-core-modules/ui/list-view";

@Component({
    moduleId: module.id,
    templateUrl: "./tips-and-tricks.component.html"
})
export class ListViewTipsComponent implements OnInit {
    items: Array<Item>;

    constructor(private _itemService: ItemService) { }

    ngOnInit(): void {
        this.items = this._itemService.getItems();
    }

    onItemTap(args: ItemEventData) {
        console.log(`Index: ${args.index}; View: ${args.view} ; Name: ${this.items[args.index].name}`);
    }

    templateSelector(item: Item, index: number, items: any) {
        return index % 2 === 0 ? "red" : "green";
    }
}

Improve this document

Demo Source


Properties

Name Type Description
items Array<any> | ItemsSource Gets or set the items collection of the ListView. The items property can be set to an array or an object defining length and getItem(index) method.
itemTemplateSelector function A function that returns the appropriate ket template based on the data item.
itemTemplates Array<KeyedTemplate> Gets or set the list of item templates for the item template selector.
separatorColor string | Color Gets or set the items separator line color of the ListView.
rowHeight Length Gets or set row height of the ListView.
iosEstimatedRowHeight Length Gets or set the estimated height of rows in the ListView. Default value: 44px

Methods

| refresh() | Forces the ListView to reload all its items. | | scrollToIndex(index: number) | Scrolls the specified item with index into view. | | scrollToIndexAnimated(index: number) | Scrolls the specified item with index into view with animation. | | isItemAtIndexVisible(index: number): boolean | Checks if specified item with index is visible. |

Events

Name Description
itemLoading Emitted when a View for the data at the specified index should be created.
itemTap Emitted when a ListView item is tapped.
loadMoreItems Emitted when the ListView is scrolled so that its last item is visible.

API References

Name Type
tns-core-modules/ui/list-view Module
ListView Class
ItemEventData Interface
ItemsSource Interface
KeyedTemplate Interface

Native Component

Android iOS
android.widget.ListView UITableView