2
votes

I am working on a small trial project with Angular2 where I have a menu and a sub-menu. Hence I need to have some kind of nested routing for sub-menu. I referred to angular.io site in the case study: Tour of heroes section but was not able to implement it successfully.

My main menu(navigation) has this routing configuration

@RouteConfig([
    { path: '/letter/...', name: 'Letter', component: LetterComponent },
    { path: '/contact', name: 'Contact', component: ContactsComponent },
    { path: '/notes', name: 'Notes', component: NotesComponent }
])

used in the UI(template) as

<ul class="sidebar-nav">
    <li id="menu-title-li">
         <div id="menu-title" class="noselect">MENU</div>
    </li>
    <li>
        <a [routerLink]="['Contacts']">Contacts</a>
    </li>
    <li>
        <a [routerLink]="['/Letter','All']">Letters</a>
    </li>
    <li>
        <a [routerLink]="['Notes']">Notes</a>
    </li>
</ul>
<router-outlet></router-outlet>

Letters section will have a sub-navigation and hence child routes.

sub-menu(sub-navigation) under letters component has been configured as

@Component({
    selector: 'letter',
    templateUrl: './app/Letter/template.html',
    directives: [RouterOutlet, ROUTER_DIRECTIVES],
    providers: [ROUTER_PROVIDERS]
})

@RouteConfig([
    { path: '/all', component: AlllettersComponent, name: 'All' , useAsDefault: true},
    { path: '/inwards', component: InwardsComponent, name: 'Inwards' },
    { path: '/outwards', component: OutwardsComponent, name: 'Outwards' }
])

used in the UI(template) as

<ul class="nav nav-tabs">
    <li role="presentation">
        <a [routerLink]="['All']">All</a>
    </li>
    <li role="presentation">
        <a [routerLink]="['Inwards']">Inwards</a>
    </li>
    <li role="presentation">
        <a [routerLink]="['Outwards']">Outwards</a>
    </li>
</ul>
<router-outlet name="letter-outlet"></router-outlet>

The main menu works and displays the corresponding template except for letters section. When I click on letters option, the corresponding template of sub-menu is loaded but in the address bar I still see http://localhost:3000/contact which I had navigated to before, I get the following error in my console, and thereafter nothing works.

angular2.dev.js:23877 Error: Component "AppComponent" has no route named "All".

I tried a lot of things that people suggested for similar problems on github and stackoverflow but nothing seems to work.

Is nested routing really supported in angular2? I went through this thread (Router Huge Flaw - Does not allow more than 1 level of nesting #6204) on github but didn't help. Is there any way to get around this problem?

2
could you try to remove providers: [ROUTER_PROVIDERS] from a child component? - dubadub
Oh! that did something.. I'm able to navigate through my child routes but 1) templates for child routes are not being loaded 2) when I try navigating to the main routes(level 1), It throws an ERROR Error: Uncaught (in promise): registerPrimaryOutlet expects to be called with an unnamed outlet. - Shri
good, could you change <router-outlet name="letter-outlet"></router-outlet> to just <router-outlet></router-outlet> as well? - dubadub
wow! and it works! perfect! i struggled for almost 2 days.. please post it as an answer.. would be helpful for many because i feel many people are struggling with this. - Shri

2 Answers

1
votes

Considering comments on the questions, the solution is:

  1. Removed providers: [ROUTER_PROVIDERS] from the child component LetterComponent which has sub-routes.
  2. Changed

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

    to

    <router-outlet></router-outlet>

Hence the final structure goes like this:

AppComponent:

@Component({
    selector: 'my-app',
    templateUrl: `
        <ul class="sidebar-nav">
            <li id="menu-title-li">
                <div id="menu-title" class="noselect">MENU</div>
            </li>
            <li>
                <a [routerLink]="['Contacts']">Contacts</a>
            </li>
            <li>
                <a [routerLink]="['/Letter','All']">Letters</a>
            </li>
            <li>
                <a [routerLink]="['Notes']">Notes</a>
            </li>
        </ul>
        <router-outlet></router-outlet>
    `,
    directives: [
        ROUTER_DIRECTIVES
    ],
    providers: [
        ROUTER_PROVIDERS
    ]
})

@RouteConfig([
    { path: '/letter/...', name: 'Letter', component: LetterComponent },
    { path: '/contact', name: 'Contact', component: ContactsComponent },
    { path: '/notes', name: 'Notes', component: NotesComponent }
])

LetterComponent(child component that has sub-routes):

@Component({
    selector: 'letter',
    templateUrl: `
        <ul class="nav nav-tabs">
            <li role="presentation">
                <a [routerLink]="['All']">All</a>
            </li>
            <li role="presentation">
                <a [routerLink]="['Inwards']">Inwards</a>
            </li>
            <li role="presentation">
                <a [routerLink]="['Outwards']">Outwards</a>
            </li>
        </ul>
        <router-outlet></router-outlet>
    `,
    directives: [RouterOutlet, ROUTER_DIRECTIVES]
})

@RouteConfig([
    { path: '/all', component: AlllettersComponent, name: 'All' , useAsDefault: true},
    { path: '/inwards', component: InwardsComponent, name: 'Inwards' },
    { path: '/outwards', component: OutwardsComponent, name: 'Outwards' }
])

Answering my own question, as somebody with same problem might find useful

0
votes

In fact when using routing you need to have route definitions in the component that you bootstrap for your application. There is no problem to define sub routes in other components.

See this question for more details:

Edit

From your error, you forgot to define a route named All in the route definition of your AppComponent class.