NativeScript-Angular Tabview Custom View inside Tabs - nativescript

I am trying to Implement NativeScript-Angular Tabview, I am able to create the Tabs with labels and Images.
I have seen examples for Nativescript using component for .xml files.
Is there any approach for Angular-NativeScript Projects.

The official doc provides it.
https://docs.nativescript.org/angular/cookbook/tab-view-ng
See an example below:
The table-view-test.ts file is your TypeScript component:
import { Component } from "#angular/core";
export class DataItem {
constructor(public itemDesc: string) {}
}
#Component({
selector: "tab-view-test",
templateUrl: "tab-view-test.html"
})
export class TabViewTest {
public items: Array<DataItem>;
constructor() {
this.items = new Array<DataItem>();
for (let i = 0; i < 5; i++) {
this.items.push(new DataItem("item " + i));
}
}
}
The tab-view-test.html file is your HTML template:
<TabView selectedIndex="1" selectedColor="#FF0000">
<StackLayout *tabItem="{title: 'Tab 01'}">
<Label text="Primary tab item"></Label>
</StackLayout>
<StackLayout *tabItem="{title: 'Tab 02'}">
<Label text="Second tab item"></Label>
</StackLayout>
</TabView>
I hope this helps!

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: Display image from url array from a collection/array using ListView

this is the JSON data that I got from a REST API:
[{
"name": "sherwin",
"field2": "value2",
"field3": "value3",
"images": [{
"image": "url1", "image":"url2"....}]
"fieldN":"valueN"
}]
... and I have the following ListItem on a page:
<ListView [items]="propertyList" class="image-list" (loaded)="onListViewLoaded($event)">
<ng-template let-item="item">
<StackLayout style="height: 200" (tap)="onItemTap(item.id)"
id="{{item.id}}" (loaded)="onItemLoaded($event, item.images)">
<StackLayout class="image-container">
<Image [src]="item.images[0].image" stretch="aspectFill" class="image-content-container"></Image>
</StackLayout>
<StackLayout class="image-caption-container">
<Label id="{{item.id}}"
[text]="item.propertyName"
class="image-caption"></Label>
<Label class="gh-list-description-sub" text="{{item.propertyType}}" textWrap="true"></Label>
</StackLayout>
</StackLayout>
</ng-template>
</ListView>
... but the problem is the image not displaying once the list item were populated. The 'labels' was displaying though. I tried data/observable on the code-behind:
export class MainComponent extends Observable implements OnInit, AfterViewInit {
private propertyList = new ObservableArray();
... some other codes here
but I am not going anywhere.
Need help.
I've seen some strange behaviour using Image on ListView in the latest NativeScript version 3.1
Images are not displayed until you scroll down and up!!
As a workaround you can use WebImage component from nativescript-web-image-cache plugin.
First install it:
tns plugin add nativescript-web-image-cache
initialize the plugin on your root component AppComponent, app.component.ts:
import { Component } from "#angular/core";
import { OnInit } from '#angular/core/core';
import { initializeOnAngular } from 'nativescript-web-image-cache';
#Component({
selector: "ns-app",
templateUrl: "app.component.html",
})
export class AppComponent implements OnInit {
ngOnInit():void {
initializeOnAngular();
}
}
In your template replace Image with WebImage:
<StackLayout class="image-container">
<WebImage [src]="item.images[0].image" stretch="aspectFill" class="image-content-container"></WebImage>
</StackLayout>

OnBlur event without the ngModel & textfield blinking

Nativescript app: I am creating dinamy TextFields.
1) Probme - When i tap on dinamicly generated text field, the keyboard shows for miliseconds and the disapears. When i tap really fast a few times then the keyboard stays.
2) How to make onChange/onBlur event on dinamicly generated TextField? Like when i update the textField i need to call a method.
Here is the current list:
(blur) Does not work:
<StackLayout col="1" row="0">
<ListView [items]="categoryService.attributes | async">
<template let-item="item" let-i="index">
<GridLayout rows="50 100">
<Label [text]="item.name"></Label>
<TextField #input *ngIf="item.type=='text'" row="1" hint="Enter Value here" [text]="item.name" (blur)="categoryService.onAttributeChange(item, item.type, null, input.value)"></ TextField>
<Switch #switch *ngIf="item.type=='checkbox'" row="1" checked="false" (checkedChange)="categoryService.onAttributeChange(item, item.type, null, switch.checked)"></Switch>
<DropDown #aa
*ngIf="item.type=='select'"
row="1"
[items]="categoryService.showAttributeValues(item.value)"
[selectedIndex]="selectedIndex"
(selectedIndexChange)="categoryService.onAttributeChange(item, item.type, aa.selectedIndex)"></DropDown>
</GridLayout>
</template>
</ListView>
</StackLayout>
Thanks!
About your second question you could use textChange method and to return $event as argument this will help you to get text for every TextField individually. You could review the sample code below. About the problem with showing the keyboard, it could be something related with the listview itemTap event. However this problem has been reproduced only on Android and still looking for possible solution.
app.component.html
<StackLayout>
<ListView [items]="myItems" (itemTap)="onItemTap($event)">
<template let-item="item" let-i="index" let-odd="odd" let-even="even">
<StackLayout [class.odd]="odd" [class.even]="even">
<Label [text]='"index: " + i'></Label>
<Label [text]='"[" + item.id +"] " + item.name'></Label>
<TextField (tap)="onTap($event)" hint="Enter text" text="" (textChange)="ontextChange($event)"></TextField>
</StackLayout>
</template>
</ListView>
</StackLayout>
app.component.ts
import {Component, Input, ChangeDetectionStrategy} from '#angular/core';
import {TextField} from "ui/text-field";
import app = require("application");
class DataItem {
constructor(public id: number, public name: string) { }
}
#Component({
selector: "my-app",
templateUrl: "app.component.html",
})
export class AppComponent {
public myItems: Array<DataItem>;
private counter: number;
public status =true;
constructor() {
this.myItems = [];
this.counter = 0;
for (var i = 0; i < 50; i++) {
this.myItems.push(new DataItem(i, "data item " + i));
this.counter = i;
}
}
public onItemTap(args) {
console.log("------------------------ ItemTapped: " + args.index);
}
public ontextChange(args){
console.log("text "+args.object.text);
}
}
I hope this helps

SegmentationBar change updating model but not updating the UI

I am having an issue with updating the UI when changing the index of a SegmentedBar component.
I started with trying to use the Segmented bar with angular/nativescript Router navigation. I could get the SegmentedBar to update the index of the bar and then fire a navigation change but the view didn't update any of the UI with dynamic data from the component.
So I simplified it a bit to have all of the UI rendered in the app.component, including the SegmentedBar. But again the same issue, I am checking for a change on the SegmentedBar and then updating the variable but its doesn't reflect the changes in the UI.
Is this a bug with the component or am I doing something wrong?
import {Component, AfterViewInit, OnInit, ViewChild, ElementRef} from "#angular/core";
import {TabsComponent} from "./components/tabs/tabs.component";
import {HTTP_PROVIDERS, Http} from '#angular/http';
import {ROUTER_DIRECTIVES, Router} from '#angular/router';
import {NS_ROUTER_DIRECTIVES} from 'nativescript-angular/router';
import {SegmentedBar, SegmentedBarItem, SelectedIndexChangedEventData} from 'ui/segmented-bar';
#Component({
selector: 'my-app',
//directives: [ROUTER_DIRECTIVES, NS_ROUTER_DIRECTIVES, TabsComponent],
//providers: [HTTP_PROVIDERS, TodoService],
template: `
<ActionBar title="Calculator" class="ui-action-bar">
<ActionItem tap="onShare"
ios.systemIcon="9" ios.position="right"
android.systemIcon="ic_menu_share" android.position="actionBar"></ActionItem>
</ActionBar>
<StackLayout>
<StackLayout class="ui-nav">
<SegmentedBar #tabs [items]="items" [selectedIndex]="selectedIndex"></SegmentedBar>
</StackLayout>
<StackLayout class="o-section o-section--edge-padding" orientation="vertical" visibility="{{ selectedIndex == 1 ? 'visible' : 'collapse' }}">
<Label text="Home" class="ui-dia-section__title"></Label>
<Label [text]="selectedIndex" class="ui-dia-section__title"></Label>
<Label text="{{selectedIndex}}" class="ui-dia-section__title"></Label>
</StackLayout>
<StackLayout class="o-section o-section--edge-padding" orientation="vertical" visibility="{{ selectedIndex == 0 ? 'visible' : 'collapse' }}">
<Label text="Glossary" class="ui-dia-section__title"></Label>
<Label [text]="selectedIndex" class="ui-dia-section__title"></Label>
</StackLayout>
</StackLayout>
`})
export class AppComponent {
selectedIndex: number;
items: Array<any>;
showHomeScreen: boolean = true;
showGlossaryScreen: boolean = false;
#ViewChild("tabs") tabs: ElementRef;
constructor() {
this.selectedIndex = 0;
this.items = [{ title: 'Calculator' }, { title: 'Glossary' }];
}
ngAfterViewInit() {
this.tabs.nativeElement.on(SegmentedBar.selectedIndexChangedEvent, (args: SelectedIndexChangedEventData) => {
switch (args.newIndex) {
case 0:
console.log('first selected, selectedIndex: ' + this.selectedIndex);
//this.router.navigateByUrl("home");
this.selectedIndex = 0;
break;
case 1:
console.log('second selected, selectedIndex: ' + this.selectedIndex);
// this.router.navigateByUrl("glossary");
this.selectedIndex = 1;
break;
case 3:
console.log('third selected')
break;
}
})
}
ngOnInit(){
console.log('ngOnInit, index: ' + this.selectedIndex);
}
}
hard to read the code but it seems to be a two way binding -banana in the box- issue ?
try: [(ngModel)]="selectedIndex"
instead of: text="{{selectedIndex}}"

Nativescript location plugin only opens location settings

I wrote some Code with nativescript and angular to watch the location.
But even though GPS on my device is switched on, geolocation.isEnabled() says false.
Plus, when running geolocation.watchLocation(..) my device only opens Location Settings. And comes back with the Error Message:
Error: Location service is not enabled or using it is not granted.
Does anybody know the reason why my app can't use location?
My app.compoment.html:
<GridLayout columns="*,*" rows="auto,auto,auto">
<Label text="Geolocation" class="title" row="0" colSpan="2"></Label>
<Button row="1" col="0" text="Start Tracking" (tap)="startTracking()"></Button>
<Button row="1" col="1" text="Stop Tracking" (tap)="stopTracking()"></Button>
<Label row="2" col="0" text="Latitude: {{latitude}}"></Label>
<Label row="2" col="1" text="Longitude: {{longitude}}"></Label>
</GridLayout>
My app.component.ts:
#Component({
selector: "my-app",
templateUrl: "app.component.html",
})
export class AppComponent {
latitude = "42";
longitude = "5";
watchId = 0;
public startTracking() {
console.log("Start Tracking");
/* Check if GPS is enabled. */
if (geolocation.isEnabled()) {
console.log("GPS is enabled.");
} else {
console.log("GPS is disabled.");
}
/* Get Location */
this.watchId = geolocation.watchLocation(function (loc) {
if (loc) {
console.log("Current location is: " + loc);
}
}, function (e) {
console.log("Error: " + e.message);
},
{desiredAccuracy: enums.Accuracy.any, updateDistance: 10, minimumUpdateTime: 1000});
}
public stopTracking() {
console.log("Stop Tracking");
if (this.watchId) {
geolocation.clearWatch(this.watchId);
this.watchId = 0;
}
}
}
Have you tried to explicitly set the permissions for geolocation service on your device?
public enableLocationTap() {
if (!geolocation.isEnabled()) {
geolocation.enableLocationRequest();
}
}
// in page.html
<StackLayout>
<Button text="enable Location" (tap)="enableLocationTap()"></Button>
</StackLayout>
After triggering the button the app should show a permission popup with allow/cancel style message.

Resources