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.
Creating Listview
HTML
<ListView [items]="countries" (itemTap)="onItemTap($event)" class="list-group">
<ng-template let-country="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.)-->
<StackLayout orientation="horizontal" class="list-group-item">
<Label text="Country: " textWrap="true"></Label>
<Label [text]="country.name"></Label>
</StackLayout>
</ng-template>
</ListView>
Note: The listview's item template can contain only a single root view container.
TypeScript
import { Component, ChangeDetectionStrategy } from "@angular/core";
class Country {
constructor(public name: string) { }
}
let europianCountries = ["Austria", "Belgium", "Bulgaria", "Croatia", "Cyprus", "Czech Republic",
"Denmark", "Estonia", "Finland", "France", "Germany", "Greece", "Hungary", "Ireland", "Italy",
"Latvia", "Lithuania", "Luxembourg", "Malta", "Netherlands", "Poland", "Portugal", "Romania", "Slovakia",
"Slovenia", "Spain", "Sweden", "United Kingdom"];
@Component({
moduleId: module.id,
templateUrl: "./creating-listview.component.html",
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CreatingListViewComponent {
public countries: Array<Country>;
constructor() {
this.countries = [];
for (let i = 0; i < europianCountries.length; i++) {
this.countries.push(new Country(europianCountries[i]));
}
}
public onItemTap(args) {
console.log("Item Tapped at cell index: " + args.index);
}
}
Customizing Listview
Demonstration of ListView customization. In the code snippets below we will show how to:
- create a custom ListView header
- create a custom Listview footer
- customize every third ListView item.
HTML
<ListView [items]="dataItems" (setupItemView)="onSetupItemView($event)" class="list-group">
<ng-template let-dataitem="item" let-i="index" let-third="third" let-header="header" let-footer="footer">
<GridLayout [class.third]="third" [class.header]="header" [class.footer]="footer" class="list-group-item">
<Label [text]="dataitem.name" android:class="label-item"></Label>
</GridLayout>
</ng-template>
</ListView>
TypeScript
import { Component, ChangeDetectionStrategy } from "@angular/core";
import { SetupItemViewArgs } from "nativescript-angular/directives";
class Item {
constructor(public name: string) { }
}
let items = ["ALL Heroes (header)", "Razor", "Rubick", "Phantom Lancer", "Legion Commander", "Brewmaster",
"Outworld Devourer", "Sniper", "Lina", "Sven", "Visage", "Undying", "Tiny", "Tidehunter", "Puck", "Ursa",
"Magnus", "Earthshaker", "Windrunner", "Techies", "Crystal Maiden", "Batrider", "Riki", "Invoker", "Venomancer",
"Timbersaw", "Wraithking", "Anti Mage", "Ancient Apparition", "Troll Warlord", "Lich", "Enchantress",
"Bristleback", "Pudge", "(footer)"];
@Component({
moduleId: module.id,
styleUrls: ["./customizing-listview.component.css"],
templateUrl: "./customizing-listview.component.html",
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CustomizingListViewComponent {
public dataItems: Array<Item>;
constructor() {
this.dataItems = [];
for (let i = 0; i < items.length; i++) {
this.dataItems.push(new Item(items[i]));
}
}
onSetupItemView(args: SetupItemViewArgs) {
args.view.context.third = (args.index % 3 === 0);
args.view.context.header = ((args.index + 1) % items.length === 1);
args.view.context.footer = (args.index + 1 === items.length);
}
}
CSS
.third {
background-color: #0099CC;
color: whitesmoke;
text-align: left;
vertical-align: center;
}
.header {
background-color: #8C489F;
color: whitesmoke;
border-radius: 3;
}
.footer {
background-color: #8C489F;
color: whitesmoke;
border-radius: 3;
}
.item {
text-align: left;
vertical-align: center;
}
Update Child Component
This example demonstrates how to use OnChanges to trigger updates in child components for data passed from parent component.
The data is pased with @Input
and the change is triggered via`ngOnChanges
with injecting SimpleChanges
in the child's constructor.
TypeScript
import { Component, Input, OnChanges, SimpleChanges } from "@angular/core";
@Component({
selector: "sdk-child-component",
moduleId: module.id,
template: `
<StackLayout orientation="horizontal">
<Label text="This is item with ID: " class="m-16" textWrap="true"></Label>
<Label [text]="myData.id" textWrap="true"></Label>
</StackLayout>
`
})
export class ItemComponent implements OnChanges {
@Input() data: any;
public myData: any;
ngOnChanges(changes: SimpleChanges) {
this.myData = changes["data"].currentValue;
}
}
@Component({
styleUrls: ["./update-child-component.component.css"],
moduleId: module.id,
templateUrl: "./update-child-component.component.html"
})
export class UpdateChildComponent {
public items: Array<any> = [];
constructor() {
for (let index = 0; index < 20; index++) {
this.items.push({ "id": index + 1 });
}
}
}
Using Async Pipe
An Angular pipe is a simple display-value transformation that can be declared in HTML.
A pipe takes an input and transforms it to a desired output. One of the built-in Angular pipes is very commonly used with ListView
like controls. This is the async pipe. The input of this pipe is either Promise
import { Component, ChangeDetectionStrategy } from "@angular/core";
import { Observable as RxObservable } from "rxjs";
export class DataItem {
constructor(public id: number, public name: string) { }
}
@Component({
moduleId: module.id,
styleUrls: ["./using-async-pipe.component.css"],
templateUrl: "./using-async-pipe.component.html",
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UsingAsyncPipeComponent {
public myItems: RxObservable<Array<DataItem>>;
constructor() {
let items = [];
for (let i = 0; i < 3; i++) {
items.push(new DataItem(i, "data item " + i));
}
let subscr;
this.myItems = RxObservable.create(subscriber => {
subscr = subscriber;
subscriber.next(items);
return function () {
console.log("Unsubscribe called!");
};
});
let counter = 2;
let intervalId = setInterval(() => {
counter++;
items.push(new DataItem(counter + 1, "data item " + (counter + 1)));
subscr.next(items);
}, 1000);
setTimeout(() => {
clearInterval(intervalId);
}, 15000);
}
}
API Reference for the ListView Class
Native Component
Android | iOS |
---|---|
android.widget.ListView | UITableView |