Progress indicator not stopping inside TabView in android platform nativescript - nativescript

Iam working the nativescript application.I have TabView with three tabs,in each tab i have progress indicator for showing api is loading and also hide the indicator after response came from api.In ios platform the indicator hide perfectly but android platform the indicator was not hide.How to solve the issue?
My TabView html code is:
<TabView [(ngModel)]="tabSelectedIndex" (selectedIndexChange)="onIndexChanged($event)" selectedTabTextColor="#40053e" androidTabsPosition="bottom" androidOffscreenTabLimit="0" iosIconRenderingMode="alwaysOriginal">
<StackLayout *tabItem="{title: 'Security', iconSource: 'res://lock'}">
<StackLayout>
<security></security>
</StackLayout>
</StackLayout>
<StackLayout *tabItem="{title: 'Personal', iconSource: 'res://boy'}">
<StackLayout>
<personal></personal>
</StackLayout>
</StackLayout>
<StackLayout *tabItem="{title: 'Payment', iconSource: 'res://card'}">
<StackLayout>
<payment></payment>
</StackLayout>
</StackLayout>
</TabView>
My TabViw ts code:
import { OnInit, Component } from "#angular/core";
import { TabView } from "tns-core-modules/ui/tab-view";
import { Page } from "ui/page";
#Component({
moduleId: module.id,
selector: "profiletab",
templateUrl: 'profiletab.component.html',
styleUrls: ['profiletab.component.css']
})
export class ProfileTabComponent implements OnInit {
private tabSelectedIndex:number;
private selectedTabName;
tabview:TabView;
constructor(private page:Page) {
this.tabSelectedIndex = 0;
this.selectedTabName = "Security Info";
}
ngOnInit(){
// this.tabview=<TabView>this.page.getViewById("tabcontrol");
// this.tabview.androidOffscreenTabLimit=1;
}
onIndexChanged(args){
let tabView = <TabView>args.object;
switch (tabView.selectedIndex) {
case 0:
this.selectedTabName = "Security Info";
break;
case 1:
this.selectedTabName = "Personal Info";
break;
case 2:
this.selectedTabName = "Payment Info";
break;
default:
break;
}
}
}
I will create indicator inside the tab1,tab2,tab3 like:
ngOnInit(){
this.loadCountries();
}
loadCountries(){
var _this = this;
if (!this.conn.getConnectionStatus()) {
Toast.makeText("Please check your internet connection").show();
return;
}
Indicator.showIndicator("Loading Please Wait...");
this.authenticationService.Get_Countries_List().then(function(response){
_this.renderData(response);
}
});
}
renderData(values){
this.authenticationService.Get_States_List(_this.dataService.userProfile.contact[0].country).then(function(response){
Indicator.hideIndicator();
}
}

You seem to create different instances while showing & hiding indicator. You must call hide of same LoadingIndicator instance on which you did call show.
Source: https://github.com/NathanWalker/nativescript-loading-indicator/issues/58
Also here is an example that demonstrates how you can do this without a plugin and always keep reference of current loading indicator no matter how many times you call show / hide simultaneously. You may even apply similar logic to maintain your LoadingIndicator instance with plugin. Refer ui-helper.ts and home-page.ts.
FYI, by nature of platform iOS seems to use a singleton which is why it works there even if you create multiple LoadingIndicator. But with Android a new progress dialog is created every time when you call show, so you must call hide on same instance.
Also as you are using Angular, I would suggest you to take advantage of framework features like Http Interceptors so you wouldn't have to create / handle indicator for each tab or each api call separately.

Related

Nativescript Vue: SearchBar on Android in focus with keyboard visible when page loads

In Android, the page loads with the keyboard expanded and the focus is on the search bar.
I am trying to keep the focus from not being there on page load. The relevant code is :
<StackLayout height="100%"
class="main-container"
>
<SearchBar ref="searchBars"
class="search-bar"
#loaded="onSearchLoaded($event)"
#textChange="onTextChanged($event)"/>
I have tried adding:
mounted() {
this.$refs.searchBars.nativeView.dismissSoftInput();
}
but this has not worked. I also tried adding this.$refs.searchBars.nativeView.dismissSoftInput()
to the #loaded event function of the searchBar.
Try this
<SearchBar #loaded="onSearchBarLoaded($event)" />
And add a method:
onSearchBarLoaded: function(event) {
if (event.object.android) {
setTimeout(() => {
event.object.dismissSoftInput();
event.object.android.clearFocus();
}, 0);
}
}
I have also tried the above method and failed. So I've did a small trick to tackle the situation.
I've added a dummy search bar and set the visibility to hidden. So the focus will shift to the dummy search bar! Here is my code.
<SearchBar
v-model="searchPhrase"
#textChange="onSearch"
#submit="onSearch"
backgroundColor="white"
#clear="clearSearch" />
<!--Dummy searchbar -->
<SearchBar v-show="false" />
You can use a method to focus on what ever you want.
searchBars() {
this.$refs.searchBars.nativeView.focus();
},

Nativescript (tap) event on a custom Angular component

I'm trying to bind a (tap) event on a custom Angular component in nativescript.
I created a custom component called 'ns-custom' and tried to bind the (tap) event to it. But it doesn't work.
In the custom component I'm doing this:
<StackLayout>
<Label text="Title"></Label>
<Label text="some text"></Label>
</StackLayout>
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'ns-custom',
templateUrl: './custom.component.html',
styleUrls: ['./custom.component.css']
})
export class CustomComponent{
constructor() { }
}
And in the parent element I'm doing this:
<ns-custom (tap)="onCustomComponentClick()"></ns-custom>
onCustomComponentClick() {
console.log('custom-component was tapped');
}
I expect the (tap) event to fire when I tap the custom component, but it does not. I built the same structure in pure Angular, and the (click) event does fire if put to a custom component.
I tried to propogate the (tap) event from the custom component like below, but then it fired twice (as expected because the tap event would propogate up to the parent component if I don't use event.stopPropagation()):
<StackLayout (tap)="emitTap()">
<Label text="Title"></Label>
<Label text="some text"></Label>
</StackLayout>
#Component({
selector: 'ns-custom',
templateUrl: './custom.component.html',
styleUrls: ['./custom.component.css']
})
export class CustomComponent{
#Output() tap = new EventEmitter();
emitTap() {
this.tap.emit();
}
}
And then catch the event on the parent component:
<ns-custom (tap)="onCustomComponentClick()"></ns-custom>
onCustomComponentClick() {
console.log('custom-component was tapped');
}
But now the tap event fires twice. I can solve it by changing the EventEmitter name to something other than 'tap' (for ex. #Output() childTapped = new EventEmitter(); and <ns-custom (childTapped)="onCustomComponentClick()"></ns-custom>) or pass the $event object on tap and then use event.stopPropagation(), but this is not elegant at all.
Any idea how to solve this simple problem in an elegant way?
This is basically answered by #mick-morely in the comments but I thought I would write up a more descriptive example and why I think it is a useful way of doing it.
You basically need to create a custom event for your custom component. While it seems tedious not to be able to re-use the tap event, it can actually improve your code quality, making it more descriptive.
So if I have a custom HoleComponent describing a "Hole", it can look like this:
Hole Template
<GridLayout rows="*" columns="*" (tap)="emitTap()">
<Label row="0" text="A very deep hole"></Label>
</GridLayout>
Hole Code
#Output() holeTap = new EventEmitter();
emitTap() {
this.holeTap.emit();
}
This Hole component can then be used by a parent like this:
Parent template
<Hole (holeTap)="onHoleTap()"></Hole>
Making the event explicitly named actually helps to make the code more readable imho. It also forces the developer to think more about the Domain they are working with which helps in conforming to the ubiquitous language if working with DDD is your thing.

How to make a NativeScript switch component’s state (ON/OFF) persist between page/app navigation based on user interaction?

My problem:
Currently, I have a switch component I’m fiddling with.
My goal is to be able to click the switch component “ON” and have it stay switched “ON” when I navigate back to the home or another page.
Attempted solutions & experimentation:
I attached a method to the native (checkedChanged) event that comes “built-in” with NativeScript switch components.
Passed the built-in (checkedChanged) event, the event data from the switch click.
Then brute forced the switch component’s “checked” attribute, to permanently be TRUE or FALSE in two separate test cases on first user click, regardless of subsequent clicks...but whenever I navigate away from the page the switch in question is reset. I know this because my flag/counter is also reset. Every time I navigate away from the page.
Any tips on how to do this. Say I click a switch “ON” in one page in the app and navigate to another page in the same app. Or close out the app completely is there any way to make the state persist? Meaning that switch stays switched ON or OFF based on human interaction/toggling?
Resources:
https://docs.nativescript.org/angular/ui/ng-ui-widgets/switch
Use application-settings to store simple value persistently. There are also options like nativescript-localstorage / SQLite for storing data persistently. application-settings may be a good choice for simple key value pairs.
import { Component } from "#angular/core";
import { setBoolean, getBoolean } from "tns-core-modules/application-settings";
#Component({
selector: "Settings",
moduleId: module.id,
template: `
<ActionBar title="Settings" class="action-bar">
</ActionBar>
<GridLayout>
<ScrollView class="page">
<StackLayout class="form">
<GridLayout columns="*,auto">
<Label text="On / Off" class="h2"></Label>
<Switch [ngModel]="value" (ngModelChange)="onSwtichChange($event)"></Switch>
</GridLayout>
</StackLayout>
</ScrollView>
</GridLayout>
`
})
export class SettingsComponent {
value = getBoolean("my-value", false);
constructor() {
}
onSwtichChange(value: boolean) {
setBoolean("my-value", value);
}
}
Playground Sample

Hide tab buttons on Nativescript-Angular TabView

I'm trying to find a way to remove the tab buttons on a element with an Angular 6 app but with no avail so far. Basically, I only want to keep the Tab contents and their swipe functionality.
Apparently there are specific android and iOS methods you can use but I'm unsure how to do that.
<TabView [(ngModel)]="tabSelectedIndex" (selectedIndexChanged)="onSelectedIndexChanged($event)" (loaded)="tabViewLoaded($event)">
<ng-container *ngFor="let article of articles" #tabView>
<StackLayout *tabItem="{title: article.id}">
<StackLayout>
<NewsDetails></NewsDetails>
</StackLayout>
</StackLayout>
</ng-container>
</TabView>
On my .ts file I can find a reference to the element like this:
#ViewChild("tabView") tabView: ElementRef;
ngAfterViewInit() {
console.dir(this.tabView.nativeElement);
}
But I have no idea what to do from now on. Any ideas? All previous questions regarding this have not worked.
Here is a sample playground link: https://play.nativescript.org/?template=play-ng&id=iK9ZTM
Use the code below with the loaded event of TabView.
onTabViewLoaded(event: EventData) {
const tabView = <TabView>event.object;
if (isIOS) {
tabView.viewController.tabBar.hidden = true;
}
if (isAndroid) {
const tabLayout = tabView.nativeViewProtected.tabLayout;
tabLayout.getLayoutParams().height = 0;
tabLayout.requestLayout();
}
}
I recently did that for a sample work I posted in Uplabs

Navigation Drawer with NativeScript

I'd like create a type of sidemenu with NativeScript, but I don't know how.
How to create a Navigation Drawer with NativeScript?
Exists any module what can do this?
There is no Drawer for now, but it's in the working AFAIK.
Meanwhile, you can check the official repo for NativeScript.
https://github.com/NativeScript/NativeScript/tree/master/apps/TelerikNEXT
Check the TelerikNext app.
Telerik announced Telerik UI for Nativescript as a plugin today.
The plugin now contains side drawer and data visualization tools. It's a commercial product but (only) the side drawer function inside it is free.
You can refer to this doc for detail information.
The drawer is here. Check out TJ Vantoll's boilerplate project to get you started...
https://github.com/tjvantoll/nativescript-template-drawer
Or a TypeScript version of that same template from Ignacio Fuentes...
https://github.com/ignaciofuentes/nativescript-template-drawer-ts
Here's an example of how to create an animated drawer menu with NativeScript 1.3 (which added an animation framework): https://github.com/emiloberg/nativescript-animated-sidebar-menu-example
I don't think it's yet available I think you need to create your own module as a view and do your own navigation (open, close).
However right out of the box I haven't found anything else in their docs.
The other thing I tried is adding a button in the header, and still I only managed to change the color of the header so I think you need to wait some more time to do these simple stuff.
Ref : I'm developing a demo app based on Buxfer and NativeScript.
Source Code: https://github.com/chehabz/Buxfer-NativeScript
I am uploading my working code. It is in Nativescript + Angular 2
drawer.html
<RadSideDrawer [drawerLocation]="currentLocation" [transition]="sideDrawerTransition"tkExampleTitle tkToggleNavButton>
<StackLayout tkDrawerContent class="sideStackLayout">
<StackLayout class="sideTitleStackLayout">
<Label text="Navigation Menu"></Label>
</StackLayout>
<StackLayout class="sideStackLayout">
<Label text="Primary" class="sideLabel sideLightGrayLabel"></Label>
<Label text="Social" class="sideLabel"></Label>
<Label text="Promotions" class="sideLabel"></Label>
<Label text="Labels" class="sideLabel sideLightGrayLabel"></Label>
<Label text="Important" class="sideLabel"></Label>
<Label text="Starred" class="sideLabel"></Label>
<Label text="Sent Mail" class="sideLabel"></Label>
<Label text="Drafts" class="sideLabel"></Label>
</StackLayout>
</StackLayout>
<StackLayout tkMainContent>
<Label [text]="mainContentText" textWrap="true" class="drawerContentText"></Label>
<Button text="OPEN DRAWER" (tap)=openDrawer()></Button>
</StackLayout>
drawer.component.ts
import {Component , OnInit, Input,ElementRef, ViewChild,ChangeDetectionStrategy,ChangeDetectorRef} from "#angular/core";
import { Router } from "#angular/router";
import { Page } from "ui/page";
import {View} from "ui/core/view";
import {Label} from "ui/label";
import {RadSideDrawerComponent, SideDrawerType} from 'nativescript-telerik-ui/sidedrawer/angular';
import {DrawerTransitionBase, SlideInOnTopTransition} from 'nativescript-telerik-ui/sidedrawer';
import * as sideDrawerModule from 'nativescript-telerik-ui/sidedrawer/';
#Component({
selector: "hello",
templateUrl: "shared/hello/app.hello.html",
styleUrls: ["shared/hello/hello.css", "css/app-common.css"],
})
export class HelloComponent implements OnInit{
private _currentNotification: string;
private _sideDrawerTransition: sideDrawerModule.DrawerTransitionBase;
constructor(private _page: Page, private _changeDetectionRef: ChangeDetectorRef) {
this._page.on("loaded", this.onLoaded, this);
}
#ViewChild(RadSideDrawerComponent) public drawerComponent: RadSideDrawerComponent;
private drawer: SideDrawerType;
ngAfterViewInit() {
this.drawer = this.drawerComponent.sideDrawer;
this._changeDetectionRef.detectChanges();
}
ngOnInit() {
}
public onLoaded(args) {
this._sideDrawerTransition = new sideDrawerModule.PushTransition();
}
public get sideDrawerTransition(): sideDrawerModule.DrawerTransitionBase {
return this._sideDrawerTransition;
}
public get currentNotification(): string {
return this._currentNotification;
}
public openDrawer() {
console.log("openDrawer");
this.drawer.showDrawer();
}
public onDrawerOpening() {
console.log("Drawer opening");
this._currentNotification = "Drawer opening";
}
public onDrawerOpened() {
console.log("Drawer opened");
this._currentNotification = "Drawer opened";
}
public onDrawerClosing() {
console.log("Drawer closing");
this._currentNotification = "Drawer closing";
}
public onDrawerClosed() {
console.log("Drawer closed");
this._currentNotification = "Drawer closed";
}
}
Don't forget to import globally in app.module.ts below:
import { SIDEDRAWER_DIRECTIVES } from "nativescript-telerik-ui/sidedrawer/angular";
and in declarations array add SIDEDRAWER_DIRECTIVES:
declarations: [
SIDEDRAWER_DIRECTIVES,
AppComponent,
...navigatableComponents
]
Check this: https://www.nativescript.org/blog/using-cross-platform-native-sidedrawer-component-in-nativescript
They now have the RadSideDrawer component
http://docs.telerik.com/devtools/nativescript-ui/Controls/NativeScript/SideDrawer/overview
Hope this helps!

Resources