Dynamic Nested router-outlet usage in Angular 4 - javascript

Dynamic Nested router-outlet usage in Angular 4
I had simple Angular CLI with dynamic routing with angular.
In my application, I had 2 different page like home and about. In that Home, I want to insert more topics with dynamic contents. so I had included nested router inside the home page. while navigating nested content it's replacing with the root element. I have attached the online sample, please check that. can anyone please provide a solution for that.
online Sample
Router configurations
import { Routes } from '#angular/router';
import { AboutComponent } from './about/about.component';
import { HomeComponent } from './home/home.component';
import { HomeNestComponent } from './home/homenest/homenest.component';
export const rootRouterConfig: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'home/homenest', component: HomeNestComponent },
];

Do the following changes in Router configurations.
import { Routes } from '#angular/router';
import { AboutComponent } from './about/about.component';
import { HomeComponent } from './home/home.component';
import { HomeNestComponent } from './home/homenest/homenest.component';
export const rootRouterConfig: Routes = [
{ path: 'home', component: HomeComponent,
children:[{ path: 'homenest', component: HomeNestComponent }]
},
{ path: 'about', component: AboutComponent },
{ path: 'homenest', component: HomeNestComponent },
];
Changes in home.component.ts.
public homeNestClick(e) {
this.router.navigateByUrl('/home/homenest');
}
https://stackblitz.com/edit/angular-tf7ru3?file=src/app/home/home.component.ts

Related

Angular 11 does not load HTML from Component

i have a question.
I have 2 router outlets in my angular app.
First one is in app.component.html and is loaded for regular users and site visitors. The router works fine and all components in it are being perfectly loaded
<ng-container *ngIf="!isAdmin">
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
</ng-container>
Here is the appRoutingModule, which is forRoot
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { HomeComponent } from './home/home.component';
import { CatalogComponent } from './movies/catalog/catalog.component';
import { NotFoundComponent } from './not-found/not-found.component';
import { AuthActivate } from './core/guards/auth.activate';
import { AboutComponent } from './about/about.component';
import { ReqComponent } from './req/req.component';
const routes: Routes = [
{
path: '',
pathMatch: 'full',
redirectTo: '/home'
},
{
path: 'home',
component: HomeComponent,
},
{
path: 'about',
component: AboutComponent
},
{
path: 'catalog',
component: CatalogComponent,
canActivate: [AuthActivate],
data: {
authenticationRequired: true,
authenticationFailureRedirectUrl: '/',
}
},
{
path: 'req',
component: ReqComponent,
canActivate: [AuthActivate],
data: {
authenticationRequired: true,
authenticationFailureRedirectUrl: '/',
}
},
// all others
{
path: '**',
component: NotFoundComponent
}
];
#NgModule({
imports: [RouterModule.forRoot(routes, {enableTracing: true})],
exports: [RouterModule]
})
export class AppRoutingModule { }
I have a second route outlet for admin users only. If user that logs is admin, the dashboard is being showed. It loads entirerly different css, header and footer. The outlet has its own routing, which works.
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { AuthActivate } from '../core/guards/auth.activate';
import { UserslistComponent } from './userslist/userslist.component';
const routes: Routes = [
{
path: 'admin-home',
component: UserslistComponent,
canActivate: [AuthActivate],
outlet: 'admin',
data: {
authenticationRequired: true,
admin: true,
authenticationFailureRedirectUrl: '/about',
}
},
{
path: 'userlist',
component: UserslistComponent,
canActivate: [AuthActivate],
outlet: 'admin',
data: {
authenticationRequired: true,
admin: true,
authenticationFailureRedirectUrl: '/about',
}
},
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AdminRoutingModule { }
the outlet in app.component.html
<ng-container *ngIf="isAdmin">
<app-adminheader></app-adminheader>
<router-outlet name="admin"></router-outlet>
<app-adminfooter></app-adminfooter>
</ng-container>
So both outlets work fine for different users. Header and footer depending on user permissions are loaded and displayed correctly.
But if i want to render HTML in the page body in between header and footer for admin, for example as the root displays, under 'userlist' load UserListComponent. the html of this userListComponent is not being displayed
I tried with 5 newly created components.
Is there any explanation on this?
Thank you for your time :)
And if checked in DOM, we see that the router-outlet is shown, but it is empty
schreenshot shows empty dom, white space, where the component userslistcomponent should be rendered and on the left side - part of the adminheadercomponent, which displays correctly
How do you access the "admin" routes?
With that implementation the URL that should show the proper admin component should look like this:
'/home/(admin:admin-home)'
are you doing that?
I'm not sure if you get the idea of secondary routes correctly :) - secondary routes (so the ones with outlet) are kind of like a child to the main route - I mean that in one time we can use two router-outlets.
In your case there are just two different route trees - one for regular users and one for admin. Therefore you shouldn't use secondary routing, but instead design the architecture like this:
<ng-container *ngIf="admin">
<app-admin-header></app-admin-header>
<router-outlet></router-outlet>
<app-admin-footer></app-admin-footer>
</ng-container>
<ng-container *ngIf="!admin">
<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>
</ng-container>
and the routes config:
const routes: Routes = [
{
path: 'home',
component: HomeComponent,
},
{
path: 'admin-home',
component: AdminHomeComponent,
},
...
]
Then you can access regular home by resolving route /home/ and admin home with /admin-home/. These two routes are on the same level - think about them as two separate ways to go :)
Thanks for the answer
Hi answering your question, i do access admin routes like this
const routes: Routes = [
{
path: 'home',
component: HomeComponent,
},
{
path: 'admin-home',
component: AdminHomeComponent,
outlet: "admin"
},
...
]
. with outlet: "admin" i enter the admin router outlet. I use different modules for different paths. For example, for user i have this routing module
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { AuthActivate } from '../core/guards/auth.activate';
import { LoginComponent } from './login/login.component';
import { ProfileComponent } from './profile/profile.component';
import { RegisterComponent } from './register/register.component';
import { EditProfileComponent } from './edit-profile/edit-profile.component';
const routes: Routes = [
{
path: 'login',
component: LoginComponent,
canActivate: [AuthActivate],
data: {
authenticationRequired: false,
authenticationFailureRedirectUrl: '/',
}
},
{
path: 'register',
component: RegisterComponent,
canActivate: [AuthActivate],
data: {
authenticationRequired: false,
authenticationFailureRedirectUrl: '/',
}
},
{
path: 'profile',
component: ProfileComponent,
canActivate: [AuthActivate],
data: {
authenticationRequired: true,
authenticationFailureRedirectUrl: '/login',
}
},
{
path: 'edit-profile',
component: EditProfileComponent,
canActivate: [AuthActivate],
data: {
authenticationRequired: true,
authenticationFailureRedirectUrl: '/',
}
},
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class UserRoutingModule { }
Meaning i do separate the routes specific for the user in this module. This works. I did separate the routes for the admin as well for user and quest and i decided to use another outlet for admins only, this is when i realised html is no longer rendered for the components, represented by this new outlet. the components i render with
user-routing.module.ts
guest-routing.module.ts
work fine, but they get the routes from the main outlet
I will try to use the main outlet for the admin routes as well, as you proposed , will see thanks :)

Lazy loading for child routes is not redirecting to child

Hi for me parent routing is working fine, but for chid routes it is not redirecting and not getting errors also
in app.routing
const routes: Routes = [
{
path: 'card',
loadChildren: './cards/cards.module#CardsModule',
canActivate: [AuthGuard]
},
{
path: 'card/:id',
loadChildren: './cards/cards.module#CardsModule',
canActivate: [AuthGuard]
}]
in card-routing:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { Cardscomponent } from './cards.component';
import { AuthGuard } from '../_services/auth.guard';
import { CardDetailsComponent } from './card-details/card-details.component';
const routes: Routes = [
{ path: '', component: Cardscomponent,
children :[
{ path: ':id', component: CardDetailsComponent}
]
}
]
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class CardsRoutingModule { }
localhost:4200/card is working
but localhost:4200/card/1234 is not working and not getting any error also, any help...
Check whether you have router-outlet in child component.
When the url updated but view not rendered, it usually comes down to missing router-outlet.
Learned that from developing a entire project with angular elements.
If you enable tracing, you can see all the router events are triggered successfully.

Angular router not loading the proper component

I am beginner with angular and I have the followings routes.
app.routing.module.ts
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { FrameComponent } from './ui/frame/frame.component';
import { NotFoundComponent } from './common/not-found/not-found.component';
const routes = [
{
path: 'login',
loadChildren: 'src/app/login/login.module#LoginModule'
},
{
path: 'dashboard',
component: FrameComponent,
loadChildren: 'src/app/dashboard/dashboard.module#DashboardModule'
},
{
path: "**",
component: NotFoundComponent,
}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
dashboard.routing.module.ts
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { OverviewComponent } from '../overview/overview.component';
const routes = [
{
path: '',
children:[
{
path: 'overview',
component: OverviewComponent,
//outlet: 'dashboard-inside'
}
]
},
];
#NgModule({
imports: [
RouterModule.forChild(routes)
],
exports: [RouterModule]
})
export class DashboardRoutingModule { }
When navigating to /dashboard it loads the FrameComponent from the AppRoutingModule.
But when navigating to /dashboard/overview it loads NotFoundComponent instead of OverviewComponent from second router.
I am still a beginner with Angular. What am I doing wrong?
I think you didn't define your routes correctly
{
path: 'dashboard',
component: FrameComponent,
loadChildren: 'src/app/dashboard/dashboard.module#DashboardModule'
}
This piece of code doesn't load lazily - you are not loading the childern over here you are just loading the component FrameComponent so angular does it for you
If your FrameComponent is part of AppModule you can just remove the loadChildren from the path and the angular will do the same routing for you
If it is not the part of AppModule then try something like this
app-routing.module.ts
{
path: 'dashboard',
loadChildren: 'src/app/dashboard/dashboard.module#DashboardModule'
}
Just load another module from the path and load the component you want from that module
dashboard-routing.module.ts
{
path: '',
component: FrameComponent,
children:[
{
path: 'overview',
component: OverviewComponent,
//outlet: 'dashboard-inside'
}
]
}
Make sure you have declared the FrameComponemt inside the DashboardModule and that will make you to load the route you want
Now if the path is /dashboard angular will load the dashboard module and check for the path '' next to the /dashboard so it will load the FrameComponent then when you try to access path /dashboard/overview routing will load the child route and OverviewComponet will be loaded
Hope everything will work good - please feel free to reach me if you have any doubts - Happy coding :)
You can remove component: FrameComponent from the dashboard route and move it into the dashboard routing module.
{
path: 'dashboard',
loadChildren: 'src/app/dashboard/dashboard.module#DashboardModule'
},
{
path: '',
component: FrameComponent,
children:[
{
path: 'overview',
component: OverviewComponent,
}
]
},
And I guess you should import your modules in core one.
Your definition in dashboard.routing.module.ts is wrong.
Try this instead:
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { OverviewComponent } from '../overview/overview.component';
const routes = [
{
path: 'overview', // <-- should be in root.
component: OverviewComponent,
},
];
#NgModule({
imports: [
RouterModule.forChild(routes)
],
exports: [RouterModule]
})
export class DashboardRoutingModule { }

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

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);
Not sure where you heard that Angular2 does not allow more than 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. 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.
Example:
//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.
Then the Admin router config may look like this:
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.
You can also do named router-outlets. An example of this is having two router-outlets side-by-side:
<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).
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)
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

Routing submenu elements Angular 2

I have a question regarding routing submenu elements in Angular 2.
The directory of my project looks like:
-app
---login
---registration
---mainApp (this is the main body of the app, with a static content as menu, with few links)
-----subMenu1 (link to some content)
-------(some files here)
-----subMenu2 (link to some content)
-------(some files here)
-----subMenu3 (link to some content)
-------(some files here)
---app.component.ts
---app.component.html
---app.module.ts
---app.routing
---index.ts
How does it works? First view is the login and there you have two possibilities, to enter the mainApp or enter registration form. It works fine. But now I need to handle the routing between the mainApp and sub items from this mainApp. The mainApp content is just a sidemenu, which doesn't disappear. It is always on screen, only content from sidemenu elements is changing.
What is my problem:
Do I need to provide another routing file to handle the routing between the mainApp static menu elements and the dynamic content? Or am I able to do it just from this file which handles routing between the app and login, registration and mainApp?
And if I have to make another routing file, how would it look like?
My actual routing file looks like:
import { Routes, RouterModule } from '#angular/router';
import { MainAppComponent} from './mainApp/index';
import { LoginComponent } from './login/index';
import { RegistrationComponent } from './registration/index';
const appRoutes: Routes = [
{ path: '', component: LoginComponent },
{ path: 'mainApp', component: MainAppComponent },
{ path: 'registration', component: RegistrationComponent },
{ path: '**', redirectTo: '' }
];
export const routing = RouterModule.forRoot(appRoutes);
Let's say that I provide another routing file, would it look like this?
import { Routes, RouterModule } from '#angular/router';
import { subMenu1Component } from './subMenu1/index';
import { subMenu2Component } from './subMenu2/index';
import { subMenu3Component } from './subMenu3/index';
const appRoutes: Routes = [
{ path: '', component: mainAppComponent},
{ path: 'subMenu1', component: subMenu1Component },
{ path: 'subMenu2', component: subMenu2Component },
{ path: 'subMenu3', component: subMenu3Component },
{ path: '**', redirectTo: '' }
];
export const routing = RouterModule.forRoot(appRoutes);
I like to split my routes off into layouts. So typically I do a secure layout and a public layout. This way I can control the authentication of the website and protect data that was meant to be secure.
In order to do this I keep a file structure as shown below,
/app.module.ts
/app.routing.ts
/layouts/secure.component.ts
/layouts/secure.component.html
/layouts/public.component.ts
/layouts/public.component.html
/secure/profile.component.ts
/secure/profile.component.html
/secure/secure.routes.ts
/public/home.component.ts
/public/home.component.html
/public/public.routes.ts
Explanation
Initially we need to register all of our components and setup the routes.
Register Components
/app.module.ts
//Layouts
import { PublicComponent } from './layouts/public.component';
import { SecureComponent } from './layouts/secure.component';
import { HomeComponent } from './public/home.component';
import { ProfileComponent } from './secure/profile.component';
#NgModule({
declarations: [
AppComponent,
PublicComponent,
SecureComponent,
HomeComponent,
ProfileComponent
],
providers: [
Guard,
Auth
]
Take special notice to the Auth under providers. This is what will help us secure the secure layout.
Next we will setup the routes.
app.routing.ts
const APP_ROUTES: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full', },
{ path: '', component: PublicComponent, data: { title: 'Public Views' }, children: PUBLIC_ROUTES },
{ path: '', component: SecureComponent, canActivate: [Guard], data: { title: 'Secure Views' }, children: SECURE_ROUTES }
];
As you can see the [Guard] is setup using the Auth provider and is a service I use to secure the secure layouts. Now that each of these routes actually have children routes we can set those routes up to control the actual navigation of our app.
It is important to understand. These routes will direct traffic to the correct layout. Then depending on the route the child routes take over. Which in your case would be your sub components.
/secure/secure.routes.ts
import { ProfileComponent } from './profile.component';
export const SECURE_ROUTES: Routes = [
{ path: '', redirectTo: 'profile', pathMatch: 'full' },
{ path: 'profile', component: ProfileComponent },
];
Remember to import your component to the routes file so it knows which class to call when the route is enabled.
For extra credit I will go ahead and throw in a service to provide auth. This will show you how to protect your routes.
guard.service.ts
import { Injectable } from '#angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { Auth } from './auth.service';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class Guard implements CanActivate {
constructor(protected router: Router, protected auth: Auth ) {}
canActivate() {
if (localStorage.getItem('access_token')) {
// logged in so return true
return true;
}
// not logged in so redirect to login page
this.router.navigate(['/home']);
return false;
}
}
By storing a token in the local storage we can check to see if it exist and authenticate the user. Once they meet the criteria they gain access to the secure routes.
Let me know if you have anymore questions.

Categories

Resources