简体   繁体   English

Angular 2子应用程序,父/子,嵌套组件,嵌套路由器插座,设计/编码

[英]Angular 2 sub apps, parent/child, nested components, nested router-outlet, design/coding

I have an Angular 2 app. 我有一个Angular 2应用程序。 The main screen (app?) looks like this... 主屏幕(app?)看起来像这样......

主应用程序屏幕

When you click items in the top menu routerLinks, new Components load into the main view router outlet. 当您单击顶部菜单routerLinks中的项目时,新组件将加载到主视图路由器插座中。 One of those links loads up an new "Admin" Module/Component with it's own routes and new router outlet... 其中一个链接加载一个新的“管理”模块/组件,它有自己的路由和新的路由器插座......

管理员应用屏幕

Then when you click the routerLinks in the left nav, new admin Components will load in the new router outlet. 然后当您单击左侧导航栏中的routerLinks时,新的管理组件将加载到新的路由器插座中。

But... 但...

Angular 2 does not allow more than 1 router outlet. Angular 2不允许超过1个路由器插座。 So clicking on any routerLink in left nav simply replaces the entire inital router outlet view. 因此,单击左侧导航栏中的任何routerLink只会替换整个初始路由器插座视图。

I've seen some SO posts (older, maybe deprecated) on using "bootstrap" to load subsequent Components, but I can't get that to work. 我已经看到使用“bootstrap”加载后续组件的一些SO帖子(更旧,可能已弃用),但我无法让它工作。 I can't even import { bootstrap } from 'anywhere at all, nothing works' . 我甚至无法import { bootstrap } from 'anywhere at all, nothing works' So maybe that's not the way to do this. 所以也许这不是这样做的方式。

How can I get the Admin sub app part to work? 如何让Admin子应用程序部分工作?

Thank you very, very much for sharing your Angular 2 expertise :-) 非常非常感谢您分享您的Angular 2专业知识:-)

EDIT: Trying suggested solutions below. 编辑:尝试以下建议的解决方案。 No matter where I put the routes, in the base app.routes.ts or in the sub-app admin.routes.ts, no matter how I format the routerLinks, I keep getting this error... 无论我把路由放在哪里,在基础app.routes.ts或子应用程序admin.routes.ts中,无论我如何格式化routerLinks,我都会收到此错误...

找不到路线

EDIT AGAIN: Here is the code in the routers and the template... 再次编辑:这是路由器和模板中的代码......

<!--
    ============================================================================
    /src/app/component/admin/admin.component.html
-->

<!-- Row for entire page columnar dispaly -->
<div class="row">

    <!-- Column 1: Left navigation, links to all admin components -->
    <div class="col col-md-4">
        <app-admin-nav></app-admin-nav>
    </div>

    <!-- Column 2: Rows of records, click to edit -->
    <div class="col col-md-8">
        <router-outlet name="admin-app"></router-outlet>
    </div>

</div>

// ============================================================================
// /src/app/app.routes.ts

import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { GameComponent } from './component/game/game.component';
import { HomeComponent } from './component/home/home.component';
import { LoginComponent } from './component/login/login.component';
import { PlayerComponent } from './component/player/player.component';
import { AuthGuard } from './service/auth/auth.service';
import { SignupComponent } from './component/signup/signup.component';
import { EmailComponent } from './component/email/email.component';
import { AdminComponent } from './component/admin/admin.component';
// import { AdminWorldComponent } from './component/admin/world/admin-world.component';
// import { AdminModuleComponent } from './component/admin/module/admin-module.component';
// import { AdminRegionComponent } from './component/admin/region/admin-region.component';

export const router: Routes = [
    { path: '', redirectTo: 'home', pathMatch: 'full' }
    , { path: 'home', component: HomeComponent }
    , { path: 'game', component: GameComponent, canActivate: [AuthGuard] }
    , { path: 'admin', component: AdminComponent, canActivate: [AuthGuard] }
    // , {
    //     path: 'admin', component: AdminComponent, canActivate: [AuthGuard],
    //     children: [
    //         { path: 'world', component: AdminWorldComponent, outlet: 'admin-app' },
    //         { path: 'module', component: AdminModuleComponent, outlet: 'admin-app' },
    //         { path: 'region', component: AdminRegionComponent, outlet: 'admin-app' }
    //     ]
    // },
    , { path: 'login', component: LoginComponent }
    , { path: 'signup', component: SignupComponent }
    , { path: 'login-email', component: EmailComponent }
    , { path: 'players', component: PlayerComponent, canActivate: [AuthGuard] }
];

export const routes: ModuleWithProviders = RouterModule.forRoot(router);

// ============================================================================
// /src/app/component/admin/admin.routes.ts

import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { AdminComponent } from './admin.component';
import { AdminWorldComponent } from './world/admin-world.component';
import { AdminModuleComponent } from './module/admin-module.component';
import { AdminRegionComponent } from './region/admin-region.component';

export const router: Routes = [
    {
        path: 'admin', component: AdminComponent,
        children: [
            { path: 'world', component: AdminWorldComponent, outlet: 'admin-app' }
            , { path: 'module', component: AdminModuleComponent, outlet: 'admin-app' }
            , { path: 'region', component: AdminRegionComponent, outlet: 'admin-app' }
        ]
    }
];

export const routes: ModuleWithProviders = RouterModule.forRoot(router);

EDIT 3: Tried changing RouterModule.forRoot to RouterModule.forChild , sadly, same error :-/ 编辑3:尝试将RouterModule.forRoot更改为RouterModule.forChild ,遗憾的是,同样的错误: - /

EDIT 4: Converted routing to use 2 routing modules. 编辑4:转换路由以使用2个路由模块。 Was hoping maybe that would make a difference, but same error. 希望可能会有所作为,但同样的错误。

New routers... 新路由器......

// ============================================================================
// /src/app/app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { GameComponent } from './component/game/game.component';
import { HomeComponent } from './component/home/home.component';
import { LoginComponent } from './component/login/login.component';
import { PlayerComponent } from './component/player/player.component';
import { AuthGuard } from './service/auth/auth.service';
import { SignupComponent } from './component/signup/signup.component';
import { EmailComponent } from './component/email/email.component';
import { AdminComponent } from './component/admin/admin.component';

export const appRoutes: Routes = [
    { path: '', redirectTo: 'home', pathMatch: 'full' }
    , { path: 'home', component: HomeComponent }
    , { path: 'game', component: GameComponent, canActivate: [AuthGuard] }
    , { path: 'admin', component: AdminComponent, canActivate: [AuthGuard] }
    // , {
    //     path: 'admin', component: AdminComponent, canActivate: [AuthGuard],
    //     children: [
    //         { path: 'world', component: AdminWorldComponent, outlet: 'admin-app' },
    //         { path: 'module', component: AdminModuleComponent, outlet: 'admin-app' },
    //         { path: 'region', component: AdminRegionComponent, outlet: 'admin-app' }
    //     ]
    // },
    , { path: 'login', component: LoginComponent }
    , { path: 'signup', component: SignupComponent }
    , { path: 'login-email', component: EmailComponent }
    , { path: 'players', component: PlayerComponent, canActivate: [AuthGuard] }
];

@NgModule({
    imports: [
        RouterModule.forRoot(appRoutes)
    ],
    exports: [
        RouterModule
    ]
})
export class AppRoutingModule { }

// ============================================================================
// /src/app/admin/admin-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AdminComponent } from './admin.component';
import { AdminWorldComponent } from './world/admin-world.component';
import { AdminModuleComponent } from './module/admin-module.component';
import { AdminRegionComponent } from './region/admin-region.component';

export const adminRoutes: Routes = [
    {
        path: 'admin', component: AdminComponent,
        children: [
            { path: 'world', component: AdminWorldComponent, outlet: 'admin-app' }
            , { path: 'module', component: AdminModuleComponent, outlet: 'admin-app' }
            , { path: 'region', component: AdminRegionComponent, outlet: 'admin-app' }
        ]
    }
];

@NgModule({
    imports: [
        RouterModule.forChild(adminRoutes)
    ],
    exports: [
        RouterModule
    ]
})
export class AdminRoutingModule { }

EDIT 5: IT'S WORKING! 编辑5:它正在工作!

Removed the routing modules, returned to exporting routes config per Tyler's suggestion. 删除了路由模块,根据Tyler的建议返回到导出路由配置。 He is right, the routing modules do not work. 他是对的,路由模块不能正常工作。 Tyler worked with me a lot so I'm accepting his answer. 泰勒和我一起工作很多,所以我接受了他的回答。 Thank you Tyler for your help! 谢谢泰勒的帮助!

Here is how you can setup a parent app with it's own router-outlet, then on the parent click a link to load up a child app with it's own new router-outlet. 以下是如何使用自己的路由器插座设置父应用程序,然后在父级单击链接以使用自己的新路由器插件加载子应用程序。 The child app loads/replaces the parent app router-outlet. 子应用程序加载/替换父应用程序路由器插座。

There is really nothing special in the parent app module or routes. 父app模块或路由中没有什么特别之处。 They're just how I had them before this post. 他们就是我在这篇文章之前的方式。

The important points to note , at least in my case today, do not use a name="" attrib in the child router-outlet. 需要注意的重要事项 ,至少在我今天的情况下, 不要在子路由器插座中使用name="" attrib。 This will cause "Error: Cannot match any routes...". 这将导致“错误:无法匹配任何路线......”。 Do not use routing modules like I tried above, this also causes "Error: Cannot match any routes...". 不要像我上面尝试的那样使用路由模块,这也会导致“错误:无法匹配任何路由......”。 Do not use outlet: 'blah' in the routes, this also causes "Error: Cannot match any routes...". 不要在路由中使用outlet: 'blah' ,这也会导致“错误:无法匹配任何路由......”。 Make sure you set up the child route config children: [] exactly as you see below in admin.routes.ts. 确保设置子路由配置children: []完全如下面admin.routes.ts中所示。 Also, note the RouterModule.forChild(router) in the child routes. 另请注意RouterModule.forChild(router) These things fixed the issue for me today. 这些事情为我今天解决了这个问题。

PARENT APP 家长APP

// ============================================================================
// src/app/app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AngularFireModule } from 'angularfire2';
import { firebaseConfig } from '../environments/firebase.config';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
// import { AppRoutingModule } from './app-routing.module';
import { routes } from './app.routes';

// Components
import { AppComponent } from './app.component';
import { HomeComponent } from './component/home/home.component';
import { GameComponent } from './component/game/game.component';
import { PlayerComponent } from './component/player/player.component';
import { LoginComponent } from './component/login/login.component';
import { SignupComponent } from './component/signup/signup.component';
import { EmailComponent } from './component/email/email.component';

// Admin Module
import { AdminModule } from './component/admin/admin.module';

// Services
import { AuthGuard } from './service/auth/auth.service';
import { AuthPlayerService } from './service/auth/auth-player.service';
import { MdbService } from './service/mongo/mdb.service';
import { PlayerMdbService } from './service/mongo/player-mdb.service';

@NgModule({
    declarations: [
        AppComponent
        , HomeComponent
        , GameComponent
        , PlayerComponent
        , LoginComponent
        , SignupComponent
        , EmailComponent
    ],
    imports: [
        BrowserModule
        , FormsModule
        , HttpModule
        , AdminModule
        , AngularFireModule.initializeApp(firebaseConfig)
        , NgbModule.forRoot()
        // , AppRoutingModule
        , routes
    ],
    providers: [
        AuthGuard
        , AuthPlayerService
        , MdbService
        , PlayerMdbService
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

// ============================================================================
// /src/app/app.routes.ts

import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { GameComponent } from './component/game/game.component';
import { HomeComponent } from './component/home/home.component';
import { LoginComponent } from './component/login/login.component';
import { PlayerComponent } from './component/player/player.component';
import { AuthGuard } from './service/auth/auth.service';
import { SignupComponent } from './component/signup/signup.component';
import { EmailComponent } from './component/email/email.component';
import { AdminComponent } from './component/admin/admin.component';

export const router: Routes = [
    { path: '', redirectTo: 'home', pathMatch: 'full' },
    { path: 'home', component: HomeComponent },
    { path: 'game', component: GameComponent, canActivate: [AuthGuard] },
    { path: 'admin', component: AdminComponent, canActivate: [AuthGuard] },
    { path: 'login', component: LoginComponent },
    { path: 'signup', component: SignupComponent },
    { path: 'login-email', component: EmailComponent },
    { path: 'players', component: PlayerComponent, canActivate: [AuthGuard] }
];

export const routes: ModuleWithProviders = RouterModule.forRoot(router);

CHILD APP 儿童APP

// ============================================================================
// /src/app/admin/admin.module.ts

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { routes } from './admin.routes';
// import { AdminRoutingModule } from './admin-routing.module';
import { AdminComponent } from './admin.component';
import { AdminRecsComponent } from './admin-recs.component';
import { AdminFormComponent } from './admin-form.component';
import { AdminNavComponent } from './admin-nav.component';

import { AdminWorldComponent } from './world/admin-world.component';
import { AdminModuleComponent } from './module/admin-module.component';
import { AdminRegionComponent } from './region/admin-region.component';

@NgModule({
    imports: [
        CommonModule
        , FormsModule
        // , AdminRoutingModule
        , routes
    ]
    , declarations: [
        AdminComponent
        , AdminNavComponent
        , AdminRecsComponent
        , AdminFormComponent
        , AdminWorldComponent
        , AdminModuleComponent
        , AdminRegionComponent
    ]
    , schemas: [CUSTOM_ELEMENTS_SCHEMA]
    , exports: [
        AdminRecsComponent
        , AdminFormComponent
        , AdminNavComponent
        // , AdminWorldComponent
        // , AdminModuleComponent
        // , AdminRegionComponent
    ]
    // , bootstrap: [AdminComponent]
})
export class AdminModule { }


// ============================================================================
// /scr/app/admin/admin.routes.ts

import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { AdminComponent } from './admin.component';
import { AdminWorldComponent } from './world/admin-world.component';
import { AdminModuleComponent } from './module/admin-module.component';
import { AdminRegionComponent } from './region/admin-region.component';

export const router: Routes = [
    {
        path: 'admin', component: AdminComponent,
        children: [
            { path: 'world', component: AdminWorldComponent },
            { path: 'module', component: AdminModuleComponent },
            { path: 'region', component: AdminRegionComponent },
        ]
    }
];

export const routes: ModuleWithProviders = RouterModule.forChild(router);

Not sure where you heard that Angular2 does not allow more than 1 router-outlet . 不知道你在哪里听说Angular2不允许超过1个router-outlet I am using several in a large application. 我在一个大型应用程序中使用了几个。

Your main app.component will have a router-outlet to handle the root routes. 您的主app.component将有一个router-outlet来处理根路由。 If one of your routes lazy-loads the Admin Module, that admin module will have it's root component that contains the side menu bar and a router-outlet for all the children routes. 如果您的某个路由延迟加载管理模块,该管理模块将拥有其根组件,其中包含侧面菜单栏和所有子路由的router-outlet

Example: 例:

//app.routes //app.routes

export const ROUTES: Routes = [
    // Main redirect
    { path: '', component: MainViewComponent },

    {
        path: 'admin',
        loadChildren: './admin/admin.module#AdminModule'
    }
]

Your MainViewComponent can contain the top navbar and a router-outlet . 您的MainViewComponent可以包含顶部导航栏和router-outlet

Then the Admin router config may look like this: 然后Admin路由器配置可能如下所示:

export const routes: Routes = [
    {
        path: '',
        component: AdminComponent,
        children: [
            { path: '', component: Component1},
            { path: 'component2', component: Component2}

        ]
    }
];

Your root component in the Admin module may contain the side bar menu and a router-outlet to show the children components. 管理模块中的根组件可能包含侧栏菜单和router-outlet用于显示子组件。

You can also do named router-outlets . 您也可以做命名的router-outlets An example of this is having two router-outlet s side-by-side: 这方面的一个例子是并排放置两个router-outlet

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

Your router config would look like this: 您的路由器配置如下所示:

{
  path: 'compose',
  component: ComposeMessageComponent,
  outlet: 'popup'
},

And you would use it like this: 你会像这样使用它:

<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>

Or clear the content with this: 或者用以下内容清除内容:

this.router.navigate([{ outlets: { popup: null }}]);

See the docs or this article for more details. 有关更多详细信息,请参阅文档本文

Hope that helps. 希望有所帮助。

Edit 编辑

When using the route config for a lazily loaded child, make sure your route configs are loaded properly in your modules. 为延迟加载的子项使用路由配置时,请确保在模块中正确加载路由配置。 The root route config will be loaded in the root AppModule with RouterModule.forRoot(routes) and the child routes are in the Child module with RouterModule.forChild(routes) . 根路由配置将在带有RouterModule.forRoot(routes)的根AppModule中加载,子路由在带有RouterModule.forChild(routes)的子模块中。

Your route config and modules need to look like this(don't create a separate module just to hold routing config): 您的路由配置和模块需要如下所示(不要创建一个单独的模块来保存路由配置):

//Admin Routes //管理员路线

export const adminRoutes: Routes = [
    {
        path: 'admin', component: AdminComponent,
        children: [
            { path: 'world', component: AdminWorldComponent, outlet: 'admin-app' }
            , { path: 'module', component: AdminModuleComponent, outlet: 'admin-app' }
            , { path: 'region', component: AdminRegionComponent, outlet: 'admin-app' }
        ]
    }
];

//Admin Module: //管理模块:

import { adminRoutes } from './admin.routes';

@NgModule({
  imports: [
    ...
    RouterModule.forChild(adminRoutes),
  ]
   ...

//App Routes(lazy load Admin module) // App Routes(延迟加载管理模块)

export const appRoutes: Routes = [
   { path: 'admin', loadChildren: './admin/admin.module#AdminModule' },
   ....

//App Module //应用模块

import { appRoutes } from './app.routes';

@NgModule({
  imports: [
    ...
    RouterModule.forRoot(appRoutes),
  ]
   ...

Hope that helps. 希望有所帮助。

Yes, there is a way to do this. 是的,有办法做到这一点。 You need to name your router outlet like: 您需要将路由器插座命名为:

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

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

And inside your router you need to define what router-outlet should route use: 在路由器内部,您需要定义路由器应该路由使用的路由器:

{
    path: 'home',  // you can keep it empty if you do not want /home
    component: 'appComponent',
    children: [
        {
            path: '',
            component: childOneComponent,
            outlet: 'child1'
        },
        {
            path: '',
            component: childTwoComponent,
            outlet: 'child2'
        }
    ]
}

Original post: Angular2 multiple router-outlet in the same template 原帖: Angular2多个路由器插座在同一个模板中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM