Stumped on navigation in tab template


#1

Can anyone see what I am doing wrong here. In this example I am trying to simply change page by tapping a button:

Here is (some of) the template

<Button text="Change Page" class="btn btn-primary" (tap)="testNav()"></Button>

And the component:

import { AppRoutingModule, ROUTES } from "../app-routing.module";
import { Router } from "@angular/router";
import { RouterExtensions } from 'nativescript-angular/router';
import { ActivatedRoute } from '@angular/router';
.
.
.
constructor(
    .
    .
    private router: Router, 
    private routerExt: RouterExtensions, 
    private route: ActivatedRoute) {
}
.
.
.
testNav() {
    this.routerExt.navigate(['../expense'], { relativeTo: this.route });
}

The routes file:

import { NgModule } from "@angular/core";
import { Routes, Router } from "@angular/router";
import { NativeScriptRouterModule } from "nativescript-angular/router";

import { QuicksnapComponent } from "./quicksnap/quicksnap.component";
import { HomeComponent } from "./home/home.component";
import { ItemDetailComponent } from "./item-detail/item-detail.component";
import { ExpenseComponent } from "./expense/expense.component";
import { ReportsComponent } from "./reports/reports.component";
import { ReportComponent } from "./reports/report.component";
import { TestComponent } from "./test/test.component";


export const COMPONENTS = [QuicksnapComponent, HomeComponent, ItemDetailComponent, ExpenseComponent, ReportsComponent, ReportComponent, TestComponent];

export const ROUTES: Routes = [
    { path: "", redirectTo: "/(homeTab:home//quicksnapTab:quicksnap//expenseTab:expense//reportsTab:reports//reportTab:report//testTab:test)", pathMatch: "full" },

    { path: "home", component: HomeComponent, outlet: "homeTab" },
    { path: "quicksnap", component: QuicksnapComponent, outlet: "quicksnapTab" },
    { path: "expense", component: ExpenseComponent, outlet: "expenseTab" },
    { path: "reports", component: ReportsComponent, outlet: "reportsTab" },
    { path: "report", component: ReportComponent, outlet: "reportTab" },
    { path: "test", component: TestComponent, outlet: "testTab" },


    { path: "item/:id", component: ItemDetailComponent, outlet: "homeTab" }
];


@NgModule({
    imports: [NativeScriptRouterModule.forRoot(ROUTES)],
    exports: [NativeScriptRouterModule]
})
export class AppRoutingModule {}

And here is the console error:

JS: ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'expense'
JS: Error: Cannot match any routes. URL Segment: 'expense'
JS:     at ApplyRedirects.noMatchError (file:///data/data/org.nativescript.myApp/files/app/tns_modules/@angular/router/bundles/router.umd.js:1440:16) [angular]
JS:     at CatchSubscriber.selector (file:///data/data/org.nativescript.myApp/files/app/tns_modules/@angular/router/bundles/router.umd.js:1421:29) [angular]
JS:     at CatchSubscriber.error (file:///data/data/org.nativescript.myApp/files/app/tns_modules/rxjs/internal/operators/catchError.js:111:31) [angular]
JS:     at MapSubscriber.Subscriber._error (file:///data/data/org.nativescript.myApp/files/app/tns_modules/rxjs/internal/Subscriber.js:142:26) [angular]
JS:     at MapSubscriber.Subscriber.error (file:///data/data/org.nativescript.myApp/files/app/tns_modules/rxjs/internal/Subscriber.js:116:18) [angular]
JS:     at MapSubscriber.Subscriber._error (file:///data/data/org.nativescript.myApp/...

This is probably very easy but I have been trying to get this working for hours and no joy yet.

Much appreciate any pointers! Let me know if I haven’t provided enough context/code.


#2

I guess you presumed the selected tab index can be changed via router, which is not true. ../expense will take you to /expenses which won’t exists.

Update TabView’s selected index to change tab.


#3

Thanks for responding.

If my TabView is in app.component.html as follows do you have an idea how I can update tabSelectedIndex from quicksnap.component.ts, for example? I can’t use this.tabSelectedIndex.

<TabView androidTabsPosition="bottom" [(ngModel)]="tabSelectedIndex" sdkExampleTitle sdkToggleNavButton>

    <page-router-outlet
        *tabItem="{title: 'Home', iconSource: getIconSource('home')}"
        name="homeTab">
    </page-router-outlet>

    <page-router-outlet
        *tabItem="{title: 'Quicksnap', iconSource: getIconSource('browse')}"
        name="quicksnapTab">
    </page-router-outlet>

    <page-router-outlet
        *tabItem="{title: 'Expense', iconSource: getIconSource('search')}"
        name="expenseTab">
    </page-router-outlet>
 
    <page-router-outlet
        *tabItem="{title: 'Reports', iconSource: getIconSource('search')}"
        name="reportsTab">
    </page-router-outlet>

    <page-router-outlet
        *tabItem="{title: 'New Report', iconSource: getIconSource('search')}"
        name="reportTab">
    </page-router-outlet>

    <page-router-outlet
        *tabItem="{title: 'Test', iconSource: getIconSource('browse')}"
        name="testTab">
    </page-router-outlet>

</TabView>

#4

You can access the TabView from any component as,

import * as app from 'application';
...
...
// will return whatever is there in your app component.
const selectedIndex = app.getRootView().selectedIndex;

Or use a Service and declare tabSelectedIndex as BehaviorSubject there.


#5

Thanks! I think I am very nearly there but not quite.

In my TabView I now have

<TabView androidTabsPosition="bottom" [(ngModel)]="selectedIndex"  id="tabview1"  sdkExampleTitle sdkToggleNavButton>

In the component I have

import * as app from 'application';
...
...
// will return whatever is there in your app component.
console.log("Root view="+app.getRootView()); // Root view=TabView<tabview1>
const selectedIndex = app.getRootView().selectedIndex;

The last line causes an error

Property 'selectedIndex' does not exist on type 'View'

Another approach I tried was put id=“tabview1” into the TabView, then in the component

var tabview1 = this.page.getViewById("tabview1");
tabview1.selectedIndex = 1;

which produces error

Property 'selectedIndex' does not exist on type 'ViewBase'

Honestly so difficult to create a link! Any ideas? Thanks.


#6

That’s simply a TypeScript error, cast your root view, (<TabView> app.getRootView()).selectedIndex.


#7

It’s working! I can simply go (for example)

(<TabView> app.getRootView()).selectedIndex=5;

Thanks very much manojdcoder!