Can we have a child router-outlet in a TabView?


#1

I’m trying to add a child router-outlet to one of my TabView tabs. However, I end up getting the error: Error: Cannot find primary outlet to load 'Tab1Child'

I’ve created a simple example app.

I have a simple router:

export const routes = [
    { path: "", redirectTo: "main", pathMatch: "full" },
    { path: "main", component: MainComponent,
        children: [
            { path: "", component: Tab1Child }
        ]
    },
    /** other paths, such as a login screen...etc **/
];

And a very basic set of components:

import {Component} from "@angular/core";

@Component({
    selector: "my-app",
    template: "<page-router-outlet></page-router-outlet>"
})
export class AppComponent {}


@Component({
    selector: "main",
    template: `<GridLayout>
                    <TabView>
                        <GridLayout *tabItem="{title: 'Tab 1'}">
                            <tab-1-component></tab-1-component>
                        </GridLayout>
                        <GridLayout *tabItem="{title: 'Tab 2'}">
                            <tab-2-component></tab-2-component>
                        </GridLayout>
                    </TabView>
                </GridLayout>`
})
export class MainComponent {}


@Component({
    selector: "tab-1-component",
    template: `<page-router-outlet></page-router-outlet>`
})
export class Tab1Component {}

@Component({
    selector: "tab-1-child",
    template: `<GridLayout>
                <Label text="Tab 1"></Label>
            </GridLayout>`
})
export class Tab1Child {}

@Component({
    selector: "tab-2-component",
    template: `<GridLayout>
				<Label text="Tab 2"></Label>
			</GridLayout>`
})
export class Tab2Component {}

Has anyone tried this before that could give me some pointers?
Or can this not be done?
Thanks.


#2

Well, unless someone comes up with some awesomely-unknown way to do this, it looks like it can’t be done. There is an open issue that mentions my exact use case:

Ability to have TabView/dedicated View (new component required) navigation. This might be impossible with the current design. But Having tabs/view be able to be easily loadable via navigation would improve things, with allowing buttons to remain on bottom but page changes…

However, I also came up with a less-than-perfect solution, which is a simple knock-off TabView:

export const routes = [
    { path: "", redirectTo: "main", pathMatch: "full" },
    { path: "main", component: MainComponent,
        children: [
            { path: "", redirectTo: "tab/0", pathMatch: "full" },
            { path: "tab/:tab", component: TabComponent }
        ]
    },
    /** other paths, such as a long screen...etc **/
];
import {Component} from "@angular/core";
import {RouterExtensions} from "nativescript-angular";
import {ActivatedRoute} from "@angular/router";

@Component({
    selector: "my-app",
    template: "<page-router-outlet></page-router-outlet>"
})
export class AppComponent {}

@Component({
    selector: "my-tabs",
    template: `<GridLayout height="60" columns="25*, 25*, 25*, 25*">
                <GridLayout col="0" horizontalAlignment="center" (tap)="setTab(0)">
                    <Label text="Tab 1" [ngClass]="{'tab-selected': selected === 0}"></Label>
                </GridLayout>
                <GridLayout col="1" horizontalAlignment="center" (tap)="setTab(1)">
                    <Label text="Tab 2" [ngClass]="{'tab-selected': selected === 1}"></Label>
                </GridLayout>
                <GridLayout col="2" horizontalAlignment="center" (tap)="setTab(2)">
                    <Label text="Tab 3" [ngClass]="{'tab-selected': selected === 2}"></Label>
                </GridLayout>
                <GridLayout col="3" horizontalAlignment="center" (tap)="setTab(3)">
                    <Label text="Tab 4" [ngClass]="{'tab-selected': selected === 3}"></Label>
                </GridLayout>
            </GridLayout>`
})
export class MyTabs {
    selected: number = 0;

    constructor(private routerExtensions: RouterExtensions) {}

    setTab(tab: number): void {
        if (tab != this.selected) {
            this.selected = tab;
            this.routerExtensions.navigate(["/main/tab/" + tab], { clearHistory: true });
        }
    }
}

@Component({
    selector: "main",
    template: `<GridLayout rows="*, auto">
                    <GridLayout row="0">
                        <router-outlet></router-outlet>            
                    </GridLayout>
                    <GridLayout row="1" backgroundColor="#5f9ea0">
                        <my-tabs></my-tabs>        
                    </GridLayout>
                </GridLayout>`
})
export class MainComponent {}


@Component({
    selector: "tab-component",
    template: `<GridLayout horizontalAlignment="center">
                <Label [text]="'Tab ' + (tab)"></Label>
            </GridLayout>`
})
export class TabComponent {
    tab: number;

    constructor(private activatedRoute: ActivatedRoute) {
        this.activatedRoute.params.subscribe(params => this.tab = parseInt(params['tab']) + 1);
    }
}

It’s not perfect, but I think it will do.


#3

Hi @jzgoda,

You can actually do that by using outlets from Angular, you can check this out here or here

Sample routes:

{
                path: 'home', component: HomeComponent,
                children: [
                    {path: '', redirectTo: 'social', pathMatch: 'full'},
                    {path: 'first', component: FirstComponent, outlet: 'first'},
                    {path: 'second', component: SecondComponent, outlet: 'second'},
                ]
 },

Sample xml of HomeComponent:

<TabView (selectedIndexChanged)="onHomeSelectedIndexChanged($event)" [selectedIndex]="homeSelectedIndex"
         selectedColor="#1083BF">
    <StackLayout *tabItem="{title: 'First'}">
        <router-outlet name="first"></router-outlet>
    </StackLayout>
    <StackLayout *tabItem="{title: 'Second'}">
        <router-outlet name="second"></router-outlet>
    </StackLayout>
</TabView>

Cheers from France :slight_smile:


#4

I’ve missed this post…

I’ve tried implementing exactly the same way as @rhanb but it’s not working for me, can you please have a look here: TabView in Angular - better example?

Cheers!

Dem