Cannot find primary outlet to load 'Localizati

2019-02-26 04:27发布

问题:

I am creating an Angular 2 RC5 application and every module is lazy loaded. When the application starts it displays the list from LocalizationListComponent, as intended, but there is a message in the console which says Cannot find primary outlet to load 'LocalizationListComponent'. Considering that the list is displayed and the error complains about the very component is very strange and unusual.

In order to resolve this I need to add <router-outlet> together with ROUTER_DIRECTIVES to every component and view that is affected by this error. The problem with this is that the list will be presented twice and the details screen is loaded under this list. This is not the behavior I want.

After this I went through Angular 2 Routing tutorial on angular.io and I checked their plunker code. Everything seems to be identical, but the error persists.

I've uploaded the application to dropbox (inactive link)

Here are the modules, routes and components (I apologize for the long list):

app.routes.ts

import { Routes, RouterModule } from "@angular/router";

const routes: Routes = [
    {
        path: "",
        redirectTo: "/localizations",
        pathMatch: "full"
    },
    {
        path: "localizations",
        loadChildren: "./app/modules/localization/localization.module",
    }
];

export const appRoutes = RouterModule.forRoot(routes);

app.module.ts

import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { appRoutes } from "../routes/app.routes"

import { AppComponent } from "../components/app.component";
import { AppNavigationComponent } from "../components/app-navigation.component";
import { AppStartComponent } from "../components/app-start.component";

import { LoggerModule } from "./logging/logger.module";
import { SharedModule } from "./shared/shared.module";

@NgModule({
    imports: [ BrowserModule, LoggerModule.forRoot(), SharedModule, appRoutes ],
    declarations: [ AppComponent, AppNavigationComponent, AppStartComponent ],
    bootstrap: [ AppComponent ]
})
export class AppModule {

}

app.component.ts

/// <reference path="../../typings/globals/node/index.d.ts" />

import { Component, OnInit, OnDestroy } from "@angular/core";
import { ActivatedRoute, Router, ROUTER_DIRECTIVES } from "@angular/router";
import { AppNavigationComponent } from "./app-navigation.component";

import { LoggerMessageType } from   "../modules/logging/models/enums/LoggerMessageType";
import { AbstractLogger } from "../modules/logging/interfaces/AbstractLogger";

@Component({
    moduleId: module.id,
    selector: "vms-localization-app",
    templateUrl: "../views/app.component.html",
    directives: [ ROUTER_DIRECTIVES ]
})
export class AppComponent {
    status: string;

    constructor(private logger: AbstractLogger) {
        this.status = "Alpha 0.1";
    }

    ngOnInit() : any {

    }

    ngOnDestroy() : any {

    }
}

localization.module.ts

import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { CommonModule } from "@angular/common";
import { FormsModule } from "@angular/forms";
import { localizationRoutes } from "./routes/localization.routes";

import { LocalizationListComponent } from "./components/localization-list.component";
import { LocalizationDetailsComponent } from "./components/localization-details.component";

import { AbstractLocalizationService } from "./interfaces/AbstractLocalizationService";
import { MockLocalizationService } from "./services/mock-localization.service";

@NgModule({
    imports: [ localizationRoutes, CommonModule, FormsModule, RouterModule ],
    declarations: [ LocalizationListComponent, LocalizationDetailsComponent ],
    providers: [ { provide: AbstractLocalizationService, useClass: MockLocalizationService } ]
})
export default class LocalizationModule {

}

localization.routes.ts

import { Routes, RouterModule } from "@angular/router";
import { LocalizationListComponent } from "../components/localization-list.component";
import { LocalizationDetailsComponent } from "../components/localization-details.component";

const routes: Routes = [
    {
        path: "",
        component: LocalizationListComponent,
        children: [
            {
                path: "localization",
                component: LocalizationListComponent
            },
            {
                path: ":id",
                component: LocalizationDetailsComponent
            },
            {
                path: "",
                component: LocalizationListComponent
            }
        ]
    }
];

export const localizationRoutes = RouterModule.forChild(routes);

localization-list.component.ts

import { Component, OnInit } from "@angular/core";
import { Localization } from '../models/localization';
import { Language } from "../models/language";

import { AbstractLocalizationService } from "../interfaces/AbstractLocalizationService";
import { AbstractLogger } from "../../logging/interfaces/AbstractLogger";
import { LoggerMessageType } from "../../logging/models/enums/LoggerMessageType";

@Component({
    moduleId: module.id,
    selector: "localization-list",
    templateUrl: "../views/localization-list.component.html"
})
export class LocalizationListComponent implements OnInit {
    localizations: Localization[];
    languages: Language[];

    constructor(private localizationService: AbstractLocalizationService,
            private logger: AbstractLogger) {

    }

    ngOnInit() : any {
        this.localizationService.getLocalizations()
            .subscribe((result: Localization[]) => {
                this.localizations = result;
                this.languages = this.localizations[0].languages;
            });
    }
}

app.component.html

<div class="container">
    <div class="page-header">
      <h1>VMS Localization<small>{{ status }}</small></h1>
      <app-navigation></app-navigation>
    </div>

    <router-outlet></router-outlet>
</div>

There must be something wrong with the above fragments (and the supplied project), but I cannot see any of it.

I also checked other questions on StackOverflow but they mostly deal with missing ROUTER_DIRECTIVES which I have in the app.component.ts

Thanks for your help people!

回答1:

I just came across an issue on GitHub (https://github.com/angular/angular/issues/10686) where it is explained that this is an intentional behavior. Every parent that has children (and it seems the same goes for loadChildren) must have it's own outlet in which to load the children.

It seems that this was not documented anywhere in the Router documentation.

UPDATE: When you declare children in a module's router, each parent must have it's own <router-outlet></router-outlet> in order to load this children. How to implement this depends on the needs. For my solution I created an empty component that just contains <router-outlet></router-outlet> and defined the route as following:

import { Routes, RouterModule } from "@angular/router"
import { SomeParentComponent } from "./app/modules/SomeModule/SomeParentComponent"
import { SomeChildComponent1 } from "./app/modules/SomeModule/SomeChild1Component"
import { SomeChildComponent2 } from "./app/modules/SomeModule/SomeChild2Component"

const routes: Routes = [
    path: "",
    component: SomeParentComponent,
    children: [
        {
            path: "",
            component: SomeChild1Component
        },
        {
            path: ":id",
            component: SomeChild2Component
        }
    ]
]

export const someModuleRoutes = RouterModule.forChild(routes);

This should do the trick as the main component route will call loadChildren pointing at SomeParentComponent.