Listview for Nativescript 7 - nativescript

Does the Listview work with Nativescript 7 with Angular I can still see it need tns-core modules?
I get a lot of errors on the nativescript-ui-listview ever since the upgrade.

In NS7 you have to use #nativescript/core instead of tns-core which is kept for the retro compatibility.
Meaning you have to replace all tns-core occurrences with the #nativescript/core.
The ListView works.

I got the RadListView to render but the swiping is not docking and the buttons not disappearing after the swipe. Here the versions I am working with whilst following some tutorial:
"dependencies": {
"#angular/animations": "~11.0.0",
"#angular/common": "~11.0.0",
"#angular/compiler": "~11.0.0",
"#angular/core": "~11.0.0",
"#angular/forms": "~11.0.0",
"#angular/platform-browser": "~11.0.0",
"#angular/platform-browser-dynamic": "~11.0.0",
"#angular/router": "~11.0.0",
"#fortawesome/fontawesome-free": "^5.15.1",
"#nativescript/angular": "~11.0.0",
"#nativescript/core": "~7.1.0",
"#nativescript/theme": "~3.0.0",
"nativescript-toasty": "^3.0.0-alpha.2",
"nativescript-ui-listview": "^9.0.4",
"nativescript-ui-sidedrawer": "^9.0.3",
"reflect-metadata": "~0.1.12",
"rxjs": "^6.6.0",
"zone.js": "~0.11.1"
}
Like Robertino mentioned you will have to import from #nativescript/core rather than tns-core-modules. Check out the component file:
import { Component, OnInit, Inject, ViewChild } from '#angular/core';
import { FavoriteService } from '../services/favorite.service';
import { Dish } from '../shared/dish';
import { ListViewEventData, RadListView, SwipeActionsEventData } from 'nativescript-ui-listview';
import { RadListViewComponent } from 'nativescript-ui-listview/angular';
import { ObservableArray } from '#nativescript/core/data/observable-array';
import { View } from '#nativescript/core/ui/core/view';
import { confirm } from "#nativescript/core/ui";
import { ToastDuration, ToastPosition, Toasty } from 'nativescript-toasty';
#Component({
selector: 'app-favorites',
moduleId: module.id,
templateUrl: './favorites.component.html',
styleUrls: ['./favorites.component.css']
})
export class FavoritesComponent implements OnInit {
favorites: ObservableArray<Dish>;
errMess: string;
#ViewChild('myListView') listViewComponent: RadListViewComponent;
constructor(private favoriteservice: FavoriteService,
#Inject('baseURL') private baseURL) {
}
ngOnInit() {
this.favoriteservice.getFavorites()
.subscribe(favorites => this.favorites = new ObservableArray(favorites),
errmess => this.errMess = errmess);
}
deleteFavorite(id: number) {
console.log('delete', id);
let options = {
title: "Confirm Delete",
message: 'Do you want to delete Dish '+ id,
okButtonText: "Yes",
cancelButtonText: "No",
neutralButtonText: "Cancel"
};
confirm(options).then((result: boolean) => {
if(result) {
this.favorites = null;
this.favoriteservice.deleteFavorite(id)
.subscribe(favorites => {
const toast = new Toasty({
text:"Deleted Dish "+ id,
duration: ToastDuration.SHORT,
position: ToastPosition.BOTTOM
});
toast.show();
this.favorites = new ObservableArray(favorites);
},
errmess => this.errMess = errmess);
}
else {
console.log('Delete cancelled');
}
});
}
public onCellSwiping(args: ListViewEventData) {
var swipeLimits = args.data.swipeLimits;
var currentItemView = args.object;
var currentView;
if(args.data.x > 200) {
}
else if (args.data.x < -200) {
}
}
public onSwipeCellStarted(args: SwipeActionsEventData) {
const swipeLimits = args.data.swipeLimits;
const swipeView = args['object'];
const leftItem = swipeView.getViewById<View>('mark-view');
const rightItem = swipeView.getViewById<View>('delete-view');
swipeLimits.left = leftItem.getMeasuredWidth();
swipeLimits.right = rightItem.getMeasuredWidth();
swipeLimits.threshold = leftItem.getMeasuredWidth()/2;
}
public onSwipeCellFinished(args: ListViewEventData) {
}
public onLeftSwipeClick(args: ListViewEventData) {
console.log('Left swipe click');
this.listViewComponent.listView.notifySwipeToExecuteFinished();
}
public onRightSwipeClick(args: ListViewEventData) {
this.deleteFavorite(args.object.bindingContext.id);
this.listViewComponent.listView.notifySwipeToExecuteFinished();
}
}
Here is the template:
<ActionBar title="My Favorites" class="action-bar">
</ActionBar>
<StackLayout class="page">
<RadListView #myListView [items]="favorites" *ngIf="favorites"
selectionBehavior="none" (itemSwipeProgressEnded)="onSwipeCellFinished($event)"
(itemSwipeProgressStarted)="onSwipeCellStarted($event)"
(itemSwipeProgressChanged)="onCellSwiping($event)"
swipeActions="true">
<ListViewLinearLayout tkListViewLayout scrollDirection="vertical"
itemInsertAnimation="Default" itemDeleteAnimation="Default">
</ListViewLinearLayout>
<ng-template tkListItemTemplate let-item="item">
<StackLayout orientation="horizontal" class="listItemStackLayout">
<Image row="0" col="0" rowSpan="2" height="60" width="60"
[src]="baseURL + item.image" class="thumb p-16"></Image>
<GridLayout rows="auto, *" columns="*">
<Label row="0" col="0" [text]="item.name" class="labelName"></Label>
<Label row="1" col="0" [text]="item.description" class="labelText" textWrap="true"></Label>
</GridLayout>
</StackLayout>
</ng-template>
<GridLayout *tkListItemSwipeTemplate columns="auto, * , auto" class="listItemSwipeGridLayout">
<StackLayout id="mark-view" class="markViewStackLayout" col="0"
(tap)="onLeftSwipeClick($event)">
<Label text="" class="swipetemplateLabel fas"
verticalAlignment="center" horizontalAlignment="center"></Label>
</StackLayout>
<StackLayout id="delete-view" class="deleteViewStackLayout" col="2"
(tap)="onRightSwipeClick($event)">
<Label text="" class="swipetemplateLabel fas"
verticalAlignment="center" horizontalAlignment="center"></Label>
</StackLayout>
</GridLayout>
</RadListView>
<ActivityIndicator busy="true" *ngIf="!(favorites || errMess)" width="50"
height="50" class="activity-indicator"></ActivityIndicator>
<Label *ngIf="errMess" [text]="'Error: ' + errMess"></Label>
</StackLayout>
And the css class:
.listItemStackLayout {
background-color: white;
padding: 10;
}
.labelName {
font-size: 20;
font-weight: bold;
margin-bottom: 8;
margin-left: 16;
}
.labelTitle {
font-size: 14;
font-weight: bold;
}
.labelText {
font-size: 12;
margin-left: 16;
}
.markViewStackLayout {
background-color: blue;
padding: 16;
}
.deleteViewStackLayout {
background-color: red;
padding: 16;
}
.listItemSwipeGridLayout {
background-color: white;
}
.swipetemplateLabel {
size: 20;
font-size: 28;
color: white;
}
There are a few lines of code you may have to remove for things to work on your end.

Related

RadAutoCompleteTextView showing "no result found error" in first build

While using RadAutoCompleteTextView in nativescript-angular app,I'm facing this weird problem:
I build my project using "tns build android --bundle".App starts but RadAutocompleteCompleteTextView shows
"no result found" although data bound to items attribute logs on terminal.
Now,if I make a minor change in my code(like delete a comment),it detect changes and auto rebuild again and this time AutocompleteView shows the data it was binding to.
Also,now if I run my app over usb debugging it runs well but if I remove usb and restart app it shows error
Error:View already has a parent
Here are the html and ts files :
app.component.html
<ActionBar title="Lestrange" class="actionbar" [height]="abarVisible">
<!-- <Image src="~/app/assets/men.png" height='50' width='50'></Image>-->
<NavigationButton icon="~/app/assets/menu.png" (tap)="onOpenDrawerTap()" [visibility]="getMenuVisible ? 'visible' : 'hidden'"></NavigationButton>
<ActionItem class="name" [visibility]="SearchVisible ? 'visible' : 'hidden'">
<StackLayout backgroundColor="#66cdaa" height="60" width="150" #action>
<RadAutoCompleteTextView [items]="searchdata" (didAutoComplete)="onDidAutoComplete($event)" *ngIf="searchdata" #aitem>
<SuggestionView tkAutoCompleteSuggestionView>
<ng-template tkSuggestionItemTemplate let-item="item">
<StackLayout orientation="vertical" padding="10">
<ImageCacheIt [src]="item.image" class='img' height='170' width='100' stretch="fill"></ImageCacheIt>
<Label [text]="item.id"></Label>
</StackLayout>
</ng-template>
</SuggestionView>
</RadAutoCompleteTextView>
</StackLayout>
</ActionItem>
<ActionItem>
<Label text="Search" color="white" (tap)="opensearch()"></Label>
</ActionItem>
</ActionBar>
<RadSideDrawer backgroundColor="transparent" id="rd" [gesturesEnabled]="sideDrawerEnabled">
<GridLayout tkDrawerContent rows="auto, *, auto" class="root-drawer-content">
<StackLayout tkDrawerContent>
<StackLayout height="56" marginTop="50" style="text-align: center; vertical-align: center;">
<Label text="Menu" fontSize="27"></Label>
</StackLayout>
<StackLayout margin="25">
<Label text="Home" [nsRouterLink]="['/hh']" padding="10" (tap)="onCloseDrawerTap()" fontSize="20" class="lbl"></Label>
<Label text="Live" [nsRouterLink]="['/lil']" padding="10" (tap)="onCloseDrawerTap()" fontSize="20" class="lbl"> </Label>
<Label text="Movies" [nsRouterLink]="['/moe']" padding="10" (tap)="onCloseDrawerTap()" fontSize="20" class="lbl"></Label>
<Label text="TV Shows" [nsRouterLink]="['/ss']" padding="10" (tap)="onCloseDrawerTap()" fontSize="20" class="lbl"></Label>
<Label text="Hindi" [nsRouterLink]="['/dhh']" padding="10" (tap)="onCloseDrawerTap()" fontSize="20" class="lbl"></Label>
</StackLayout>
<Label text="Logout" color="lightgray" padding="15" style="horizontal-align: center" (tap)="logout()" fontSize="20"> </Label>
</StackLayout>
</GridLayout>
<page-router-outlet tkMainContent actionBarVisibility="never"></page-router-outlet>
</RadSideDrawer>
app.component.ts:`
import {registerElement} from "nativescript-angular/element-registry";
registerElement("exoplayer", () => require("nativescript-exoplayer").Video);
import { Component,OnInit, ViewChild,AfterViewInit,OnChanges,AfterContentInit} from "#angular/core";
//import { isAndroid } from "tns-core-modules/platform";
import { Page } from "tns-core-modules/ui/page";
import { RouterExtensions } from "nativescript-angular/router";
import * as ApplicationSettings from "#nativescript/core/application-settings";
const firebase = require("nativescript-plugin-firebase");
import { RadSideDrawerComponent} from "nativescript-ui-sidedrawer/angular";
import {FirebaseService} from '../app/services/firebase.service';
import { RadAutoCompleteTextViewComponent } from "nativescript-ui-autocomplete/angular";
import { TokenModel, AutoCompleteCompletionMode, AutoCompleteDisplayMode, AutoCompleteSuggestMode } from "nativescript-ui-autocomplete";
import { ObservableArray } from "tns-core-modules/data/observable-array"
import { Observable } from "rxjs";
import "rxjs/add/operator/merge";
import { MovieModel } from "./models/movie.model";
import { NavigationExtras } from "#angular/router";
​
#Component({
selector: "ns-app",
templateUrl: "app.component.html"
})
export class AppComponent implements OnInit,AfterViewInit,AfterContentInit{
​
#ViewChild(RadSideDrawerComponent, { static: false }) public drawerComponent: RadSideDrawerComponent;
​
public isAuth: boolean;
public sideDrawerEnabled:boolean=false;
public getMenuVisible:boolean=true;
public abarVisible:number=70;
public searchvar: boolean;
public searchdata: ObservableArray<MovieModel>;
public searchdata1: ObservableArray<MovieModel>;
​
public datas$:Observable<any>;
public SearchVisible: boolean=false;
​
constructor(private page: Page,public router:RouterExtensions,public firebaseService: FirebaseService) { }
ngAfterContentInit(): void {
}
ngAfterViewInit(): void {
// //ApplicationSettings.setBoolean("authenticated", false);
// console.log(this.searchdata);
// //},2);
}
​
​
​
public ngOnInit() {
firebase.init({
}).then(
() => {
console.log("firebase.init done");
},
error => {
console.log(`firebase.init error: ${error}`);
}
);
/////////////////////////////////////////////////////
// console.log("fir"+this.getMenuVisible);
this.firebaseService.AbarVisibleEnabled.subscribe(x=>this.abarVisible=x);
this.firebaseService.SearchVisibleEnabled.subscribe(x=>this.SearchVisible=x);
​
this.firebaseService.sideDrawerEnabled.subscribe(x=>this.sideDrawerEnabled=x);
this.firebaseService.MenuVisibleEnabled.subscribe(y=>this.getMenuVisible=y);
// console.log("fir"+this.getMenuVisible);
this.searchdata = new ObservableArray<MovieModel>();
this.datas$ = <any>this.firebaseService.getMyWishList('/index');
// this.searchdata=this.firebaseService.fetchsearchdata();
// this.searchdata1=this.searchdata;
// console.log(this.searchdata);
// // setTimeout(()=>{
this.datas$.subscribe(datas=>{
datas.map(x=>{console.log(x);
this.searchdata.push(new MovieModel(x.id,x.c,x.img));
})
});
//this.drawer = this.drawerComponent.sideDrawer;
if(this.router.router.url==='/login'){
this.isAuth=true;
}else{
this.isAuth=false;
}
}
​
public onDidAutoComplete(args) {
this.SearchVisible=false;
console.log(args.text.split(",")[0]);
console.log(args.text.split(",")[1].trim());
this.searchvar=false;
​
let navigationExtras: NavigationExtras = {
queryParams: {
"showId": args.text.split(",")[0].trim(),
"fromRoute":args.text.split(",")[1].trim()
​
}
};
this.router.navigate(["/show-detail"],navigationExtras);
}
onOpenDrawerTap() {
this.drawerComponent.sideDrawer.showDrawer();
}
onCloseDrawerTap() {
this.drawerComponent.sideDrawer.closeDrawer();
}
​
get dataItems(): ObservableArray<MovieModel> {
return this.searchdata;
}
opensearch(){
this.SearchVisible=!this.SearchVisible;
}
​
public logout() {
this.onCloseDrawerTap();
ApplicationSettings.setBoolean("authenticated", false);
//ApplicationSettings.remove("authenticated");
this.router.navigate(["/login"], { clearHistory: true });
}
}
`
Although I don't have much knowledge about angular lifecycle hooks but I have a feeling that its about angular hooks ,So I tried to use differnet hooks but to no avail.Please help me find the issue in my code.Thanks in advance.
It looks like you have an unpaired </StackLayout> tag in your html file. It is right after `.
I think you should remove that and see if that resolves the issue.
Hope this helps!

Nativescript Composite components

Criei um component com estilo .SCSS porem ele não aplica o estilo.
precisar ser especificamente .css o aquivo de estilo?
(English translation)
I created a component with .SCSS style but it does not apply the style. need to be specifically .css the style file?
{
...,
"devDependencies": {
"css-loader": "^3.4.2",
"nativescript-dev-webpack": "~1.5.1",
"node-sass": "^4.13.1",
"sass-loader": "^8.0.2",
"typescript": "~3.5.3",
"webpack": "^4.42.1"
},
...
}
.container-search {
margin: 8;
padding: 0 5;
border-radius: 30;
background-color: white;
textField {
border-width: 1;
border-color: transparent;
font-size: 14;
margin: 0;
color: #333;
}
button {
width: 35;
height: 35;
padding: 0;
margin: 0;
color: #999;
border-radius: 100%;
background-color: #fff;
font-size: 16;
font-weight: 700;
}
}
<StackLayout class="container-search" loaded="onLoaded">
<GridLayout rows="auto" columns="auto,*,auto" >
<Button row="0" col="0" id="searchButton" text="" class="las" tap="{{ onSearchSubmit }}" />
<TextField row="0" col="1" id="searchField" hint="Pesquise.." autocorrect="false" returnKeyType="search" returnPress="{{ onSearchSubmit }}" />
<Button row="0" col="2" id="searchClear" text="" class="las" tap="{{ onSearchClear }}" visibility="hidden" />
</GridLayout>
</StackLayout>
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout/stack-layout";
import { TextField } from "tns-core-modules/ui/text-field/text-field";
import { Button } from "tns-core-modules/ui/button/button";
import { Internationalization } from "~/pages/#shared/utilities/internationalization";
export class SearchBar {
public static shared: SearchBar;
private static searchField: TextField;
private static searchButton: Button;
private static searchClear: Button;
public static onLoaded(args: any) {
const innerComponent = args.object as StackLayout;
const bindingContext = {...innerComponent.bindingContext};
SearchBar.searchField = innerComponent.getViewById("searchField") as TextField;
SearchBar.searchButton = innerComponent.getViewById("searchButton") as Button;
SearchBar.searchClear = innerComponent.getViewById("searchClear") as Button;
SearchBar.searchField.on("textChange", SearchBar.onTextChangeST);
bindingContext.internationalization = Internationalization.singleton().getData();
bindingContext.onSearchSubmit = SearchBar.onSearchSubmit;
bindingContext.onSearchClear = SearchBar.onSearchClear;
innerComponent.bindingContext = bindingContext;
SearchBar.shared = SearchBar;
}
public static get onSearchSubmit(): (args: any) => void {
return SearchBar.onSearchSubmitST;
}
public static get onSearchClear(): (args: any) => void {
return SearchBar.onSearchClearST;
}
// Auxiliaries Methods
private static onTextChangeST(args: any) {
const text = SearchBar.searchField.text;
const bindingContext = args.object.page.bindingContext;
if(text != ""){
SearchBar.searchClear.visibility = "visible";
} else {
SearchBar.searchClear.visibility = "collapse";
bindingContext.search("");
}
}
private static onSearchSubmitST(args: any) {
const text = SearchBar.searchField.text;
const bindingContext = args.object.page.bindingContext;
if(args.object.id == "searchButton") {
setTimeout(() => {
SearchBar.searchField.dismissSoftInput();
}, 100);
}
const result = bindingContext.search(text);
if(result == 0) { ()=>{} }
}
private static onSearchClearST(args: any) {
const bindingContext = args.object.page.bindingContext;
SearchBar.searchField.text = "";
bindingContext.searchClear();
}
}
export const onLoaded = SearchBar.onLoaded;
Not necessary .css I think You need to include your file in the webpack this is a link to show you an exemple :How to inciude a local html file in a webview in nativescript main-page.js?
Second option is :Migrate the project to the latest version wiht tns migrate if it is not done .
Third option : You need to compile the .scss files with :
npm install --save-dev node-sass sass-loader
I am letting you this link : https://www.tjvantoll.com/2019/08/30/nativescript-sass/
In the case you have not seen this you may try this link
https://www.tjvantoll.com/2019/08/30/nativescript-sass/

Adding fade in/out to grid row selection

In this StackBlitz I have a Kendo for Angular grid. When you click on the button, the second row will be selected after half second, and unselected automatically after two seconds.
What I need is the selected row to fade-in on selection and fade-out after two seconds, is this possible?
#Component({
selector: 'my-app',
template: `
<button type="button" (click)="select()">Select</button>
<kendo-grid [data]="gridData" [height]="410"
kendoGridSelectBy="ProductID" [(selectedKeys)]="selection">
<kendo-grid-column field="ProductID" title="ID" width="40">
</kendo-grid-column>
<kendo-grid-column field="ProductName" title="Name" width="250">
</kendo-grid-column>
</kendo-grid>
`
})
export class AppComponent {
selection: number[] = [];
public gridData: any[] = products;
select(){
setTimeout(() => {
this.selection = [2];
setTimeout(() => {
this.selection = [];
}, 2000);
}, 500);
}
}
Not sure if this is the most optimized solution, but you can use:
rowClass (https://www.telerik.com/kendo-angular-ui/components/grid/api/GridComponent/#toc-rowclass)
selectionChange (https://www.telerik.com/kendo-angular-ui/components/grid/api/GridComponent/#toc-selectionchange)
With that function and event, you can add a custom class to your selected rows and use CSS for the fade animation. Your code would be something like this:
import { Component } from '#angular/core';
import { products } from './products';
import { Component, ViewEncapsulation } from '#angular/core';
import { RowClassArgs } from '#progress/kendo-angular-grid';
#Component({
selector: 'my-app',
encapsulation: ViewEncapsulation.None,
styles: [`
.k-grid tr.isSelected {
background-color: #41f4df;
transition: background-color 1s linear;
}
.k-grid tr.isNotSelected {
background-color: transparent;
transition: background-color 2s linear;
}
`],
template: `
<kendo-grid [data]="gridData"
[height]="410"
kendoGridSelectBy="ProductID"
[rowClass]="rowCallback"
(selectionChange)="onSelect($event)">
<kendo-grid-column field="ProductID" title="ID" width="40">
</kendo-grid-column>
<kendo-grid-column field="ProductName" title="Name" width="250">
</kendo-grid-column>
</kendo-grid>
`
})
export class AppComponent {
public gridData: any[] = products;
public onSelect(e){
setTimeout(() => {
e.selectedRows[0].dataItem.isSelected = true;
setTimeout(() => {
e.selectedRows[0].dataItem.isSelected = false;
}, 2000);
}, 500);
}
public rowCallback(context: RowClassArgs) {
if (context.dataItem.isSelected){
return {
isSelected: true,
};
} else {
return {isNotSelected: true};
}
}
}
-- EDIT --
Just noticed that you want to do that only with the second row. In that case, you can replace line e.selectedRows[0].dataItem.isSelected = true; with: products[1].isSelected = true;.
And use your button to call the onSelect function.

Nativescript Show element while scrolling up in ListView - parallax effect

I would like to get an advice on how to go around implementing a feature seen in many apps like Whatsapp or Facebook, where you have a list and a header which is not visible always, but is gradually shown when the user begins to scroll upwards from any place within a list.
In whatsapp and facebook the upward scrolling gesture causes the Search bar to slowly appear at the top of the screen, while the list itself is not scrolling until the search bar appears at full (at least this is the android implementation).
I need an advice on how to implement this using Nativescript angular with Telerik RadListView (android + ios). As far as I know, putting a ListView inside a ScrollView generally is not advised by telerik.
Thanks!
Edit: I learned it is called a parallax effect, and found examples of it in native android, however, not in nativescript with ListView (did find an example with ScrollView and regular StackLayout, not with a ListView inside).
You can check the available "Implementing a Parallax Scroll Effect" sample in the 'Samples' section of the official NativeScript marketplace website that shows how to implement just that effect. Just go to Market.nativescript.org and search for 'parallax'. Also there is a plugin that provides such functionality but I am not sure of its quality.
Here is an example of a scrollable parallax effect RadListView implemented using Angular (no ScrollView needed). It also provides an example of sticking the list header at the top.
Please me know if it works for you.
Component template:
<GridLayout class="page">
<RadListView (scrolled)="onScroll($event)" [items]="dataItems" itemReorder="true"
(itemReordered)="onItemReordered($event)">
<ListViewGridLayout tkListViewLayout scrollDirection="Vertical" spanCount="1" ios:itemHeight="150"
dynamicItemSize="false"></ListViewGridLayout>
<ng-template tkListItemTemplate let-item="item">
<StackLayout orientation="vertical">
<!-- list item content goes here -->
</StackLayout>
</ng-template>
<ng-template tkListViewHeader>
<StackLayout>
<GridLayout #fixedHeaderContainer class="fixed-header-container">
<label text="Fixed Content" verticalAlignment="center"></label>
</GridLayout>
<StackLayout class="list-header-container">
<StackLayout #listHeaderContainer>
<label text="List Title"></label>
</StackLayout>
</StackLayout>
</StackLayout>
</ng-template>
</RadListView>
<GridLayout verticalAlignment="top" [height]="dockContainerHeight" [opacity]="dockContainerOpacity">
<FlexboxLayout justifyContent="flex-start" alignItems="center" class="docked-label-wrapper">
<button class="fas" text=""></button>
<StackLayout flexGrow="1" height="100%" [opacity]="dockContentOpacity" orientation="horizontal">
<label text="List Title"></label>
</StackLayout>
</FlexboxLayout>
</GridLayout>
Component scss:
.fixed-header-container {
height: 200;
padding: 0 16;
background-color: green;
label {
font-size: 30;
font-weight: 700;
color: $white;
}
}
.list-header-container {
margin-top: -12;
border-radius: 12 12 0 0;
background-color: #ffffff;
label {
margin: 16 0;
font-size: 22;
color: black;
vertical-align: center;
}
.smaller-label {
font-size: 12;
color: #909090;
}
}
RadListView {
height: 100%;
background-color: #ffffff;
}
.docked-label-wrapper {
margin: 0 0 10;
background-color: #ffffff;
.fas {
margin: 0;
font-size: 18;
}
label {
font-size: 18;
color: black;
vertical-align: center;
}
}
Component ts:
import { Component, ElementRef, OnInit, ViewChild } from '#angular/core';
import { ListViewEventData, ListViewScrollEventData } from 'nativescript-ui-listview';
import { DataItem, DataItemService } from './data-items.service';
export const DOCK_HEADER_HEIGHT = 58;
#Component({
moduleId: module.id,
selector: 'app-comp-name',
templateUrl: './comp-name.component.html',
styleUrls: ['./comp-name.component.scss']
})
export class CompNameComponent implements OnInit {
dataItems: DataItem[];
dockContainerHeight = DOCK_HEADER_HEIGHT;
dockContainerOpacity = 0;
dockContentOpacity = 0;
#ViewChild('fixedHeaderContainer', { static: false })
fixedHeaderContainerRef: ElementRef;
#ViewChild('listHeaderContainer')
listHeaderContainerRef: ElementRef;
constructor(private _dataItemService: DataItemService) {}
ngOnInit(): void {
this.dataItems = this._dataItemService.getDataItems();
}
onItemReordered(args: ListViewEventData) {
console.log('Item reordered. Old index: ' + args.index + ' ' + 'new index: ' + args.data.targetIndex);
}
onScroll(args: ListViewScrollEventData) {
if (!this.fixedHeaderContainerRef) {
return;
}
const offset = args.scrollOffset < 0 ? 0 : args.scrollOffset;
const fixedHeaderHeight = this.fixedHeaderContainerRef.nativeElement.getActualSize().height;
this.applyFixedHeaderTransition(offset);
this.applyTitleTransition(offset, fixedHeaderHeight);
this.applyDockHeaderTransition(offset, fixedHeaderHeight);
}
private applyFixedHeaderTransition(scrollOffset: number) {
this.fixedHeaderContainerRef.nativeElement.translateY = scrollOffset;
}
private applyTitleTransition(scrollOffset: number, fixedHeaderHeight: number) {
const maxHeightChange = fixedHeaderHeight - DOCK_HEADER_HEIGHT;
const titleElement = this.listHeaderContainerRef.nativeElement;
if (maxHeightChange < scrollOffset) {
titleElement.translateX = -(scrollOffset - maxHeightChange) / 1.2;
titleElement.translateY = -(scrollOffset - maxHeightChange) * 2;
titleElement.scaleX = 1 - (scrollOffset - maxHeightChange) / fixedHeaderHeight;
titleElement.scaleY = 1 - (scrollOffset - maxHeightChange) / fixedHeaderHeight;
} else {
titleElement.translateX = 0;
titleElement.translateY = 0;
titleElement.scaleX = 1;
titleElement.scaleY = 1;
}
}
private applyDockHeaderTransition(scrollOffset: number, fixedHeaderHeight: number) {
const maxHeightChange = fixedHeaderHeight - DOCK_HEADER_HEIGHT;
const containerOpacity = 1 - scrollOffset / maxHeightChange;
this.dockContainerOpacity = containerOpacity <= 0 ? 1 : 0;
this.dockContentOpacity = (scrollOffset - (fixedHeaderHeight - DOCK_HEADER_HEIGHT)) / DOCK_HEADER_HEIGHT - 0.2;
}
}

Filter ListView using angular2 in NativeScript

I am new to nativescript and angular2. I want to filter listview using textfield input entered by user. in angular version 1, we used to do it like
<input type="text" ng-model="userinput">
<div ng-repeat="x in items | filter : userinput">
</div>
how can i do this using angular2 in nativescript?
my listview is:
<ListView [items]="myItems" class="list-group">
<template let-item="item">
<StackLayout>
<Label [text]='item.Department' class="list-group-item"></Label>
</StackLayout>
</template>
</ListView>
and in my component:
export class someComponent {
public myItem: Array<any>;
public isLoading: boolean;
public constructor(private http: Http) {
this.myItem = [];
this.isLoading = true;
}
public ngOnInit()
{
this.http.get("some_api_url")
.map(result => result.json())
.do(result => console.log(JSON.stringify(result)))
.subscribe(result => {
this.myItem = result;
this.isLoading = false;
}, error => {
console.log("ERROR: ", error);
});
}
}
You had to create a pipe for filtering first, something like:
#Pipe({
name: 'filter'
})
#Injectable()
export class FilterPipe implements PipeTransform {
transform(items: any[], field : string, value : string): any[] {
if (!items) return [];
return items.filter(it => it[field] == value);
}
}
Usage:
<li *ngFor="let it of its | filter : 'name' : 'value or variable'">{{it}}</li>
The nativescript ui listview filtering is slow when the data is huge and it does "remove" the no match item. I change a bit code to make it fast and only show filtered data. :)
happy coding :)
Page class="page">
<StackLayout orientation="vertical">
<GridLayout rows="auto,auto,*,auto">
<StackLayout class="form" row="0" orientation="horizontal" width="100%">
<TextField hint="Search..." class="input"
id= "searchstr"
[(ngModel)]="searchstr"
width="80%"></TextField>
<Button class="btn-sm btn-primary btn-active"
id="btnSearch"
(tap)="onSearchTap($event)"
width="20%" height="40" >
<FormattedString>
<Span [text]="iconval" class="icon"></Span>
</FormattedString>
</Button>
</StackLayout>
<StackLayout row="1" orientation="horizontal" width="100%" backgroundcolor="black">
<Label text="CODE" width="25%" class="caption"></Label>
<Label text="NAME" width="75%" class="caption"></Label>
</StackLayout>
<ScrollView row="2" tkExampleTitle tkToggleNavButton>
<RadListView [items]="dataItems"
(itemLoading)="onItemLoading($event)">
<ListViewLinearLayout
tkListViewLayout scrollDirection="Vertical"
itemInsertAnimation="Slide"
itemDeleteAnimation="Slide"></ListViewLinearLayout>
<ng-template tkListItemTemplate let-item="item" let-i="index" let-odd="odd" let-even="even">
<StackLayout class="list-item"
(tap)="onItemTap(item)"
orientation="horizontal" width="100%">
<Label [text]="item.custCode" width="25%"></Label>
<Label [text]="item.custName" width="75%"></Label>
</StackLayout>
</ng-template>
</RadListView>
</ScrollView>
</GridLayout>
</StackLayout>
</Page>
import { Component, OnInit } from '#angular/core';
import { ListViewEventData } from 'nativescript-ui-listview';
import { Color } from 'tns-core-modules/color/color';
import { APIService } from '~/app/core/services';
import { Observable } from 'rxjs';
import { CustProfileLight } from '~/app/core/model';
import { ObservableArray } from 'tns-core-modules/data/observable-array/observable-array';
#Component({
selector: 'ns-customer-lookup',
templateUrl: './customer-lookup.component.html',
styleUrls: ['./customer-lookup.component.css'],
moduleId: module.id,
})
export class CustomerLookupComponent implements OnInit {
private _dataItems: ObservableArray<CustProfileLight>;
customer$:Observable<CustProfileLight>
iconval:string;
search:string;
searchstr:string;
items:any;
//private _myFilteringFunc: (item: any) => any;
constructor(private serv:APIService) { }
ngOnInit() {
this.iconval = String.fromCharCode(0xe986);
this.serv.getCustomer().subscribe(resp=>{
this.items = resp;
this._dataItems = new ObservableArray<CustProfileLight>(resp);
})
}
get dataItems(): ObservableArray<CustProfileLight> {
return this._dataItems;
}
onItemLoading(args: ListViewEventData){
if (args.index % 2 === 0) {
args.view.backgroundColor = new Color("#b3ecff");
}
}
onItemTap(item){
}
onSearchTap(e){
const key =this.searchstr;
console.log(key);
let data= this.items.filter(item=>item.custCode.includes(key) ||
item.custName.includes(key) ||
item.address1.includes(key) ||
item.address2.includes(key) ||
item.address3.includes(key) ||
item.address4.includes(key) ||
item.city.includes(key) ||
item.state.includes(key) ||
item.postalCode.includes(key) ||
item.tel.includes(key) ||
item.fax.includes(key) ||
item.contactPerson.includes(key)
);
this._dataItems = new ObservableArray<CustProfileLight>(data);
}
// get FilteringFunc(): (item: any) => any {
// return this._myFilteringFunc;
// }
// set FilteringFunc(value: (item: any) => any) {
// this._myFilteringFunc = value;
// }
}

Resources