How to make back navigation by tap NativeScript? - nativescript

My template is:
<ActionBar class="action-bar">
<NavigationButton android.systemIcon="ic_menu_back" text="Back" (tap)="goBack()"></NavigationButton>
</ActionBar>
How to write function goBack() to move back?

Since you're using Angular, you can use RouterExtensions from the nativescript-angular package. Specifically, call routerExtensions.back(). Here's a complete inline example:
import { Component } from '#angular/core';
import { RouterExtensions } from 'nativescript-angular/router';
#Component({
selector: 'example',
moduleId: module.id,
template: `<ActionBar class="action-bar">
<NavigationButton android.systemIcon="ic_menu_back" text="Back" (tap)="routerExtensions.back()"></NavigationButton>
</ActionBar>`,
})
export class ExampleComponent {
constructor(public routerExtensions: RouterExtensions) {
}
}

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!

Why is this route not routing through `page-router-outlet`?

I'm trying to have a component that has an ActionBar and child components that are accessed by page-router-outlet.
My HTML for the parent component is as follows:
<ActionBar class="action-bar">
<NavigationButton ios:visibility="collapsed" icon="res://menu" (tap)="onDrawerButtonTap()"></NavigationButton>
<ActionItem icon="res://navigation/menu" android:visibility="collapsed" (tap)="onDrawerButtonTap()"
ios.position="left">
</ActionItem>
<Label class="action-bar-title" text="Example Text"></Label>
</ActionBar>
<RadSideDrawer #drawer showOverNavigation="true" [drawerTransition]="sideDrawerTransition">
<StackLayout tkDrawerContent>
<MyDrawer [selectedPage]="'Settings'"></MyDrawer>
</StackLayout>
<StackLayout class="page page-content" tkMainContent>
<page-router-outlet></page-router-outlet>
</StackLayout>
</RadSideDrawer>
My routing-module for the parent component looks like:
import {NgModule} from '#angular/core';
import {Routes} from '#angular/router';
import {NativeScriptRouterModule} from 'nativescript-angular/router';
import {HomeComponent} from './home.component';
import {DashboardComponent} from '../dashboard/dashboard.component';
import {Dashboard2Component} from '../dashboard2/dashboard.component';
const routes: Routes = [
{
path: '',
component: HomeComponent,
children: [
{path: '', component: DashboardComponent},
{path: 'projects', component: Dashboard2Component},
]
}
];
#NgModule({
imports: [NativeScriptRouterModule.forChild(routes)],
exports: [NativeScriptRouterModule]
})
export class HomeRoutingModule {
}
export const routedComponents = [
HomeComponent
];
However, when I route to /projects, it brings me to a new page with a new actionbar
It's my understanding that this is because page-router-outlet creates a new page, that being said, I want to be able to navigate back from one child component back to the previous child component. Is this possible in {N}?
Make the main template for your app as a component...
app-template.component.html:
<ActionBar class="action-bar">
<NavigationButton class="action-item" icon="res://ic_menu" (tap)="toggleDrawer()"></NavigationButton>
<StackLayout class="action-bar-title">
<Label [text]="title"></Label>
</StackLayout>
</ActionBar>
<RadSideDrawer showOverNavigation="true">
<ScrollView tkDrawerContent class="sidedrawer-center" tkDrawerClosed="onDrawerClosed" tkDrawerClosing="onDrawerClosing" tkDrawerOpened="onDrawerOpened" tkDrawerOpening="onDrawerOpening">
<StackLayout>
<StackLayout class="sidedrawer-header">
<Label text="blah blah blah" class="text-left text-capitalize font-weight-bold text-primary" textWrap="true"></Label>
</StackLayout>
<StackLayout class="sidedrawer-content">
<GridLayout (tap)="closeDrawer()" nsRouterLinkActive="active" [nsRouterLinkActiveOptions]="{exact: true}" [nsRouterLink]="['/']" class="sidedrawer-list-item" pageTransition="fade" rows="auto" columns="auto, *">
<Label class="sidedrawer-list-item-text" row="0" col="1" text="Home"></Label>
</GridLayout>
<GridLayout (tap)="closeDrawer()" nsRouterLinkActive="active" [nsRouterLink]="['/settings']" class="sidedrawer-list-item" pageTransition="fade" rows="auto" columns="auto, *">
<Label class="sidedrawer-list-item-text" row="0" col="1" text="Settings"></Label>
</GridLayout>
</StackLayout>
</StackLayout>
</ScrollView>
<StackLayout tkMainContent class="page">
<ng-content></ng-content>
</StackLayout>
</RadSideDrawer>
app-template.component.ts:
import { Component, ViewChild, Input, OnInit } from "#angular/core";
import { RadSideDrawer, PushTransition } from "nativescript-telerik-ui/sidedrawer";
import { RadSideDrawerComponent } from "nativescript-telerik-ui/sidedrawer/angular";
#Component({
selector: "app-template",
moduleId: module.id,
templateUrl: './app-template.component.html'
})
export class AppTemplateComponent {
canToggleDrawer: boolean = true;
constructor() { }
#Input() title: string = 'MyApp';
#ViewChild(RadSideDrawerComponent) drawerComponent: RadSideDrawerComponent;
drawer: RadSideDrawer;
ngOnInit() {}
ngAfterViewInit() {
this.drawer = this.drawerComponent.sideDrawer;
this.drawer.drawerTransition = new PushTransition();
}
toggleDrawer() {
if (this.canToggleDrawer) {
this.drawer.toggleDrawerState();
}
}
closeDrawer() {
this.drawer.closeDrawer();
}
}
then on your child views, just call it as <app-template> and put your content inside it. This way, you can keep your drawer menu in one file only, and still be able to use the back buttons...

Admin on rest custom button

I would like to make a custom button that would be used to fetch. I want the button to be usable like this:
export const LogList = (props) => (
<List {...props} perPage={100} title="Logs and Reports" filters={< FileFilter/>}>
<Datagrid>
<TextField source="inputfile" label="Input File" />
<TextField source="cycle" label="Cycle" />
<TextField source="job" label="Job" />
<TextField source="name" label="File Name" />
<ShowButton/>
<JobCancel/>
</Datagrid>
</List>
);
Where is my button is <JobCancel/> up above (similar to how ShowButton is implemented). I want the button to fetch(controller_service/archivedfiles/${id}, { method: 'DELETE', body:{} }); on click.
Is something like this possible?
P.S. I am new to Admin on rest
You can also find an example for custom actions in the demo repository for reviews (accept, reject): https://github.com/marmelab/admin-on-rest-demo/tree/master/src/reviews
Misread your question. So am editing my answer.
I have custom button for my list view.
It's a straightforward Redux connected component.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import RaisedButton from 'material-ui/RaisedButton';
import { editorAssign as editorAssignAction} from '../customActions/EditorAssignActions'
import styles from '../styles/styles'
class EditorAssignButton extends Component {
constructor(props){
super(props);
this.state = { disabled: false };
}
handleClick = () => {
const { editorAssign, record } = this.props
editorAssign(record.id) //call the action
this.setState({
disabled: true
})
}
render() {
const editorAssignStyle = styles.editorAssignStyle;
return (<RaisedButton label='Add To Edit'
onClick={this.handleClick}
disabled={ this.state.disabled }
primary={true}
/>)
}
}
EditorAssignButton.propTypes = {
editorAssign: PropTypes.func,
record: PropTypes.object
}
export default connect(null, {
editorAssign: editorAssignAction
})(EditorAssignButton)
AOR has documentation on how to write custom actions and trigger side effects with Sagas.
https://marmelab.com/admin-on-rest/Actions.html
DELETE is an action available with AOR Rest so your requirement should be quite standard.
Here is the EditorAssign view. It is a straightforward list and datagrid component
import React from 'react';
import { ReferenceField,
ChipField,
SelectInput,
ReferenceInput,
TextField,
List,
Filter,
Datagrid} from 'admin-on-rest';
import AssignTaleEditToSelf from '../buttons/AssignTaleEditToSelf'
const EditorAssignView = (props) => {
return (
<List {...props} title="Fresh Tales" perPage={20} sort={{ field: 'id', order: 'ASC' }} filter={{"status": "NEW"}} filters={ <EditorFilter /> } >
<Datagrid >
<TextField source="id" label="id" style={{ textAlign: 'center'}} />
<TextField source="taleTitle" label="Title" />
<TextField source="taleText" label="Content" style={{maxWidth: '150px'}} />
<ReferenceField label="Writer" source="writer_id" reference="appUsers">
<ChipField source="name" />
</ReferenceField>
<AssignTaleEditToSelf label="Assign To Self" />
</CustomDatagrid>
</List>
)
}
}

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>

NativeScript-Angular Tabview Custom View inside Tabs

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!

Resources