I have an Angular 2 app. The main screen (app?) looks like this...
When you click items in the top menu routerLinks, new Components load into the main view router outlet. 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.
But...
Angular 2 does not allow more than 1 router outlet. So clicking on any routerLink in left nav simply replaces the entire inital router outlet view.
I've seen some SO posts (older, maybe deprecated) on using "bootstrap" to load subsequent Components, but I can't get that to work. I can't even 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?
Thank you very, very much for sharing your Angular 2 expertise :-)
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...
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 :-/
EDIT 4: Converted routing to use 2 routing modules. 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!
Removed the routing modules, returned to exporting routes config per Tyler's suggestion. 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. 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. 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...". Make sure you set up the child route config children: []
exactly as you see below in admin.routes.ts. Also, note the RouterModule.forChild(router)
in the child routes. These things fixed the issue for me today.
PARENT 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
// ============================================================================
// /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);