TabView and nested router-outlet "Cannot activate an already activated outlet"


#1

I have some nested router-outlets in a tabview, when I activate tab2 the nested outlet loads the components just fine but when I switch to tab3 and activate it’s outlet and then back to tab2 the outlet in tab2 doesen’t work anymore?

tabs.html

<TabView 
    #tabView 
    tabsBackgroundColor="#f57c00" 
    selectedTabTextColor="black"
    [(ngModel)]="selectedIndex"
    selectedIndex="0"
    (selectedIndexChanged)="tabIndexChange($event)">

    <StackLayout *tabItem="{title: 'Tab 1'}" (loaded)="tab1Loaded($event)" (unloaded)="tab1Unloaded($event)">
        
        <Label text="Tab 1" textWrap="true" horizontalAlignment="center" class="p-10"></Label>
        
        <!-- <tab-1 *ngIf="activeTab === 0"></tab-1> -->
        
    </StackLayout>

    <StackLayout *tabItem="{title: 'Tab 2'}" (loaded)="tab2Loaded($event)" (unloaded)="tab2Unloaded($event)">
        
        <Label text="Tab 2" textWrap="true" horizontalAlignment="center" class="p-30"></Label>
        
        <StackLayout *ngIf="activeTab === 1">

            <Button text="Tab 2 A" class="btn btn-primary" (tap)="tab2GoTo('tab2a')"></Button>
            <Button text="Tab 2 B" class="btn btn-primary" (tap)="tab2GoTo('tab2b')"></Button>

            <router-outlet name="tab2outlet"></router-outlet>

        </StackLayout>
        
    </StackLayout>

    <StackLayout *tabItem="{title: 'Tab 3'}" (loaded)="tab3Loaded($event)" (unloaded)="tab3Unloaded($event)">
            
        <Label text="Tab 3" textWrap="true" horizontalAlignment="center" class="p-30"></Label>
            
        <StackLayout *ngIf="activeTab === 2">

            <Button text="Tab 3 A" class="btn btn-primary" (tap)="tab3GoTo('tab3a')"></Button>
            <Button text="Tab 3 B" class="btn btn-primary" (tap)="tab3GoTo('tab3b')"></Button>

            <router-outlet name="tab3outlet"></router-outlet>

        </StackLayout>

    </StackLayout>

</TabView>
const routes: Routes = [
    { path: "", component: TabsComponent, children: [
        { path: "tab1", loadChildren: "./tabs/tab-1/tab-1.module#Tab1Module" },
        { path: "tab2", children: [
            { path: "tab2a", component: CmpAComponent, outlet: "tab2outlet" },
            { path: "tab2b", component: CmpBComponent, outlet: "tab2outlet" }
        ] },
        { path: "tab3", children: [
            { path: "", component: CmpEComponent, outlet: "tab3outlet" },
            { path: "tab3a", component: CmpCComponent, outlet: "tab3outlet" },
            { path: "tab3b", component: CmpDComponent, outlet: "tab3outlet" }
        ] }
    ] }
];

#2

Hey @johnnydoe, thanks for reporting this. I’ll bump this back to the top with this comment.

One idea for future reference: if you can get this code running in a NativeScript Playground (see https://play.nativescript.org/) it’ll be a lot easier for the community to jump in and help you out.


#3

Ok I wasn’t aware of that, thanks


#4

Ok here is the playground

(don’t work when i scan in the phone?)


#5

Thanks for getting this working in the playground! I’ll pass this link around.


#6

Hi @johnnydoe,

I managed to make it work by bringing the tab routes under one array of children:

path: "tabs", children: [
    { path: "tab2a", component: CmpAComponent, outlet: "tab2outlet" },
    { path: "tab2b", component: CmpBComponent, outlet: "tab2outlet" },
    { path: "tab3a", component: CmpCComponent, outlet: "tab3outlet" },
    { path: "tab3b", component: CmpDComponent, outlet: "tab3outlet" }
]

as this seemed to be causing the problem.

I am going to check with the dev team, as I believe that we still should be able to navigate between children of separate branches.

See the working solution here: https://play.nativescript.org/?id=aoikCxKL300ah8T6qWoe0

Does this solution work for you?

As a side note: you should avoid setting your default navigation path to a lazy loaded module, as this will slow down the load of your app. The default path should always be eagerly loaded. :slight_smile:


#7

Thank you so much, yes it does!
One more question though, if I want to have CmpAComponent loaded when first visiting tab2 and CmpCComponent loaded when visiting tab3, how would I do that?

Note taken, thank you :slight_smile:


#8

You could check my article on the subject: Nested router-outlet

Usually the trick is to set the routeroutlets in the default path like:
redirectTo: '/home/(catoutlet:cats//dogoutlet:dogs)'


#9

Ok got it now, I was doing it in home-routing.module instead of app-routing.module.

Thank you!