0

I am using a <page-router-outlet></page-router-outlet> and <BottomNavigation></BottomNavigation> setup for tabs in my Nativescript Angular project, and am having trouble navigating from 1 child tab route to another child tab route.

So here is the app-routing.module.ts:

const routes: Routes = [
    { path: '', redirectTo: '/auth', pathMatch: 'full' },
    { path: 'auth', component: AuthComponent },
    { path: 'individual-tasks', component: SpecificTasksComponent },
    {
        path: 'tabs',
        component: TabsComponent,
        children: [
            {
                path: 'feed',
                loadChildren: '~/app/pages/feed/feed.module#FeedModule',
                component: NSEmptyOutletComponent,
                outlet: 'feedTab'
            },
            {
                path: 'notification',
                loadChildren: '~/app/pages/notification/notification.module#NotificationModule',
                component: NSEmptyOutletComponent,
                outlet: 'notificationTab'
            },
            {
                path: 'create',
                loadChildren: '~/app/pages/create/create.module#CreateModule',
                component: NSEmptyOutletComponent,
                outlet: 'createTab'
            },
            {
                path: 'profile',
                loadChildren: '~/app/pages/profile/profile.module#ProfileModule',
                component: NSEmptyOutletComponent,
                outlet: 'profileTab'
            }
        ]
    }
];

And I am currently trying to navigate from within the create tab module to the feed tab module. Here is the create-routing.module.ts:

const routes: Routes = [
    { path: '', redirectTo: 'create', pathMatch: 'full' },
    { path: 'create', component: CreateComponent },
    { path: 'create-tasks', component: CreateTasksComponent },
    { path: 'create-preview', component: CreatePreviewComponent }
];

So if I am currently within the create-preview route how can I navigate back to the "tabs/feed" outlet thats in the app-routing.module.ts?

I have been trying this:

        this.router.navigate([
            '../tabs', {
                outlets: { feedTab: ['feed'] }, relativeTo: this.activatedRoute
            }
        ]);

but even though I am explicitly writing that the navigation should be to the feedTab, it still navigates to the starting outlet (profile) instead of the feed outlet. It is like the outlet stated is entirely ignored... Any ideas???

3
  • 1
    I don't think the router gives you the ability to switch tabs. You will have to update selectedIndex of tab and then navigate to particular tab you like. Commented Nov 29, 2019 at 18:12
  • i think @Manoj is correct...Now I will have to figure out how to update the selectedIndex from within one of its child components Commented Nov 30, 2019 at 1:52
  • Use a service with behavior subject. Listen to the subject from parent component, update the value in child component. Commented Nov 30, 2019 at 3:25

3 Answers 3

2

One of the comments asked to clarify how to use a BehaviorSubject for this purpose, so I'll post this code in case it can help someone in the future. This will show how to use a rxjs BehaviorSubject to listen for tab changes and also provide a way to change the current tab of the BottomNavigation from anywhere within the app using this service.

The purpose of this service is to provide a central place where the BottomNavigation UI element can be accessed throughout the app. It can:

  • Use an ElementRef of BottomNavigation so the nativeElement can be accessed to get or change the current tab of the BottomNavigation element.
  • Provides an rxjs BehaviorSubject observable that allows consumers of this service to subscribe to and then be notified of BottomNavigation selectedIndexChanged events. The newIndex and oldIndex are emitted from this rxjs BehaviorSubject observable on every BottomNavigation selectedIndexChanged event.

NOTE: In the component that has the BottomNavigation element in its template (app.component.ts in this example), it must give this NavigationService the reference to the BottomNavigation it needs in its ngAfterViewInit life cycle hook like: this._navigationService.bottomNavigationRef = this.navRef; (see snippet in app.component.ts below)

// navigation.service.ts

import { ElementRef, Injectable, OnDestroy } from '@angular/core';

import { BottomNavigation, SelectedIndexChangedEventData } from '@nativescript/core';

import { BehaviorSubject, Subscription } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class NavigationService implements OnDestroy {
  private _bottomNavigationRef: ElementRef<BottomNavigation>;
  private _subscription: Subscription;
  private callbackSelIndexChgEv;
  /** rxjs BehaviorSubject observable to track the current tab of the BottomNavigation */
  bottomNavigationTab$: BehaviorSubject<{ newIndex: number; oldIndex: number }>;

  constructor() {
    // Must initialize rxjs BehaviorSubject observable with initial value.
    this.bottomNavigationTab$ = new BehaviorSubject({
      newIndex: -1,
      oldIndex: -1,
    });

    // Logs the current tab per this service.
    this._subscription = this.bottomNavigationTab$.subscribe((value) => {
      console.log(
        `NavigationService -> The BottomNavigation current tab index is now:
            newIndex: "${value.newIndex}"
            oldIndex: "${value.oldIndex}"`
      );
    });
  }

  ngOnDestroy(): void {
    this._subscription.unsubscribe();
    this._bottomNavigationRef.nativeElement.off(
      BottomNavigation.selectedIndexChangedEvent,
      this.callbackSelIndexChgEv
    );
  }

  get bottomNavigationRef(): ElementRef<BottomNavigation> {
    return this._bottomNavigationRef;
  }

  set bottomNavigationRef(bottomNavRef: ElementRef<BottomNavigation>) {
    this._bottomNavigationRef = bottomNavRef;

    this.callbackSelIndexChgEv = (
      $event: SelectedIndexChangedEventData
    ): void => {
      /* Update the current tab of the rxjs BehaviorSubject Observable */
      this.bottomNavigationTab$.next({
        newIndex: $event.newIndex,
        oldIndex: $event.oldIndex,
      });
    };

    this._bottomNavigationRef.nativeElement.on(
      BottomNavigation.selectedIndexChangedEvent,
      this.callbackSelIndexChgEv
    );
  }
}

// app.component.ts (partial file)

// ...
 @ViewChild('bottomNav') navRef: ElementRef<BottomNavigation>;
// ...
ngAfterViewInit(): void {
    // Gives the NavigationService the reference to the BottomNavigation it needs.
    this._navigationService.bottomNavigationRef = this.navRef;
}
// ...
<!-- app.component.html (partial file just to show #bottomNav) -->
<BottomNavigation #bottomNav>
<!-- ... -->
</BottomNavigation>
// another.component.ts

import { Component, OnDestroy, OnInit } from '@angular/core';

import { Subscription } from 'rxjs';

import { NavigationService } from './navigation.service';

@Component({
  selector: 'app-another-component',
  templateUrl: './another.component.html',
  styleUrls: ['./another.component.scss']
})
export class AnotherComponent implements OnDestroy, OnInit {
  private _subscription: Subscription;

  constructor(private _navigationService: NavigationService) {}

  ngOnInit(): void {
    // Example using BehaviorSubject Observable:
    this._subscription = this._navigationService.bottomNavigationTab$.subscribe(
      (selectedTab) => {
        console.log(`This component knows that the BottomNavigation current tab is now: ${selectedTab.newIndex} and the old tab was: ${selectedTab.oldIndex}`);

        if (selectedTab.newIndex === 2) {
          // do something ...
        }
      }
    );
  }

  ngOnDestroy(): void {
    // unsubscribe from BehaviorSubject Observable
    this._subscription.unsubscribe();
  }

  // Example changing the BottomNavigation tab from another component:
  changeTab(tab: number): void {
    this._navigationService.bottomNavigationRef.nativeElement.selectedIndex = tab;
  }

}

rxjs BehaviorSubject documentation: https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject

Sign up to request clarification or add additional context in comments.

Comments

1

I don't think the router gives you the ability to switch tabs. You will have to update selectedIndex of BottomNavigation and then navigate to particular tab you like.

To update selectedIndex from child component, use a service with a BehaviorSubject. Listen to the subject from parent component, update the value from child component.

3 Comments

Thank you @Manoj that worked and I was able to navigate to different indexes with the BehaviorSubject model...However, after the navigation, everything in that tab that I navigate too has disappeared. So it just shows a blank white page after navigating, but if i navigate to another tab and then back, all of the components come back and are visible again. Does this ring any bells?
@WJosh Vetter Hi Manoj, Josh can you clarify how the solution with BehaviorSubject works?
@LimyandiVicoTrico I posted an answer showing how BehaviorSubject works with example code.
0

Try this :

You need to remove this.activatedRoute from navigate(), which is assigning current route before the routing path which you have provided now.

 this.router.navigate(['../tabs/feed', {
       outlets: {  primary: ['feed'], feedTab: ['feed'] }
    }
 ])

you can read more about outlets here and follow this blog for more details.

Hope this helps.. :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.