I try to configure routing in angular 8.x application, with lazy loading and named outlets. I have the next configuration:
main-layout.html
<header>
<app-top-menu></app-top-menu>
</header>
<mat-sidenav-container autosize="true" id="app-main-layout">
<mat-sidenav opened mode="side">
<app-left-menu></app-left-menu>
</mat-sidenav>
<router-outlet name="toolbar"></router-outlet>
<div id="app-layout-content">
<router-outlet></router-outlet>
</div>
</mat-sidenav-container>
app-router.module.ts
const routes: Routes = [
{
path: '', component: MainLayoutComponent, canActivate: [RouteGuardService],
children: [
{
path: 'databases',
loadChildren: () => import('./feature-modules/database-search/database-search.module')
.then(m => m.DatabaseSearchModule)
}
]
}
];
#NgModule({
imports: [RouterModule.forRoot(routes, { enableTracing: true })],
exports: [RouterModule]
})
export class AppRoutingModule { }
There is a lazy loaded module router:
databases-search-routing.module.ts
const routes: Routes = [
{
path: 'index',
component: DatabaseListComponent,
children: [
{
path: '',
component: DatabaseListActionsMenuComponent,
outlet: 'toolbar'
}
]
},
{
path: 'mappings',
component: MappingsComponent,
children: [
{
path: '',
component: DatabaseListActionsMenuComponent,
outlet: 'toolbar'
}
]
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DatabaseSearchRoutingModule { }
The aim here is to load different toolbar for different views. So /databases/index should load DatabaseListComponent into 'main' router outlet and DatabaseListActionsMenuComponent into named 'toolbar' outlet.
However, it is not working.
The main router outlet is populated correctly but the named outlet isn't. I can't figure out what I'm doing wrong.
What is the right configuration for this case?
You should try to put the primary outlet routes, and the toolbar outlet routes at the same depth, and have a componentless parent route for both, like this:
const routes: Routes = [{
path: 'index',
children: [{
path: '',
component: DatabaseListComponent
}, {
path: '',
component: DatabaseListActionsMenuComponent,
outlet: 'toolbar'
}
]
}, {
path: 'mappings',
children: [{
path: '',
component: MappingsComponent
}, {
path: '',
component: DatabaseListActionsMenuComponent,
outlet: 'toolbar'
}
]
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DatabaseSearchRoutingModule {}
Related
I have a sidebar with some links. The sidebar is located at the /dashboard route. The links on the sidebar are direct children to /dashboard. I now want to render the children of /dashboard inside the main router-outlet. I have no idea on how to approach this.
The following are some code snippets to elaborate my question further
My routing structure
const routes: Routes = [
{
path: '',
component: LoginComponent,
},
{
path: 'dashboard',
component: DashboardComponent,
children: [
{
path: 'roles',
component: RolesComponent,
},
{
path: 'workgroups',
component: WorkgroupsComponent,
children: [
{
path: 'savewg',
component: WgDetailsComponent,
},
]
},
{
path: 'users',
component: UsersComponent,
},
],
},
];
App component
<!-- Main app component -->
<div class="app-view">
<router-outlet></router-outlet>
</div>
Login.html
<button mat-raised-button color="warn" class="login-field" (click)="login(email, password)"
<!-- rest of code ommited for brevity -->
Login.ts
public login(email: string, password: string) {
this.router.navigate(['dashboard'], { replaceUrl: true });
}
Workgroup Component html
<button mat-raised-button color="warn" [routerLink]="['savewg']">
<mat-icon>add</mat-icon>
New
</button>
<!-- Code ommited for brevity -->
<router-outlet></router-outlet>
<div class="workgroup-filters">
<mat-form-field appearance="outline">
<!-- rest of Code ommited for brevity -->
When I click on the new button in the workgroup component, I want it to navigate me to the savewg component view and replace the content in the workgroup component.
Any suggestions on how I can tackle this will be appreciated
Modules are only allow one main router-outlet per module. You will have to create a separate module for workgroups path and lazy load it. The workgroups module will have its own routing file and its own router outlet where you will load all your routes from your workgroup module. See below stackblitz for a working example.
app-routing.module.ts
const routes: Routes = [
...
{
path: 'workgroups',
loadChildren: () => import('./workgroups/workgroups.module').then(m => m.WorkgroupsModule)
},
...
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
workgroups-routing.module.ts
const routes: Routes = [
{
path: '',
component: WorkgroupsComponent,
children: [
{
path: 'savewg',
component: WgDetailsComponent
},
{
path: '**',
redirectTo: 'savewg',
pathMatch: 'full'
}
]
},
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class WorkgroupsRoutingModule { }
workgroups.module.ts
#NgModule({
imports: [
CommonModule,
WorkgroupsRoutingModule
],
declarations: [
WorkgroupsComponent,
WgDetailsComponent
]
})
export class WorkgroupsModule { }
Below are resources for lazy loading modules and a stackblitz example.
https://stackblitz.com/edit/angular-ivy-hbogtn
https://www.freakyjolly.com/angular-nested-routing-with-multiple-routeroutlet-using-loadchildren-having-own-router-modules-example-application/#.X3IQa3WYXmE
I found a better solution to this. It turns out that Angular will load the empty path route as the default route and there is no need to worry about router outlet anymore. I modified my app-routing.module.ts in the following way:
const routes: Routes = [
{
path: '',
component: LoginComponent,
},
{
path: 'dashboard',
component: DashboardComponent,
children: [
{
path: 'roles',
component: RolesComponent,
},
{
path: 'workgroups',
children: [
{
path: 'savewg',
component: WgDetailsComponent,
},
{
path: '',
component: WorkgroupsComponent,
},
],
},
{
path: 'users',
component: UsersComponent,
},
],
},
];
As you can see, I've added an empty path as a child in the
workgroups component This may not be perfect, more approaches and
solutions are welcome.
My app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'updateBooking', loadChildren: () => import('./update-booking/update-booking.module').then(m => m.UpdateBookingModule) },
{ path: 'booking', loadChildren: () => import('./booking/booking.module').then(m => m.BookingModule) }
];
#NgModule({
imports: [RouterModule.forRoot(routes, { enableTracing: true })],
exports: [RouterModule]
})
export class AppRoutingModule { }
lazy loaded Booking module's routing:
const routes: Routes = [
{ path: '', redirectTo: 'bookingdashboard' },
{
path: 'bookingdashboard', component: BookingDashboardComponent,
children: [
{ path: '', redirectTo: 'associateinfo' },
{
path: 'associateinfo', component: AssociateInfoComponent
},
{
path: 'agenda', component: AgendaComponent
},
{
path: 'zone', component: ZoneComponent
},
]
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class BookingRoutingModule { }
I am on associate info page with url http://localhost:4200/booking/bookingdashboard/associateinfo
From this page when I try to navigate to agenda page using this._route.navigate(['../agenda' ]); I am getting error Cannot match any routes. URL Segment: 'agenda'
Error: Cannot match any routes. URL Segment: 'agenda'
However If I try to navigate from HTML file using [routerLink]="[ '../agenda']" its navigating to agenda page
You are navigating to only component specific route path, you should follow route as module-path/component-path
this._route.navigate(['booking/bookingdashboard/agenda' ]);
try
this._route.navigate(['/booking/bookingdashboard/agenda']);
After the link parameters array, add an object with a relativeTo
property set to the ActivatedRoute. The router then calculates the
target URL based on the active route's location.
constructor(private _router: Router, private route: ActivatedRoute){}
this._router.navigate(['../agenda'], { relativeTo: this.route })
In my app-routing.module I have a lazy module:
const appRoutes: Routes = [
{ path: 'profile/:id',
loadChildren: './profile/profile-standalone/profile-standalone.module#ProfileStandaloneModule',
}
];
Here is my profile--standalone-routing.module-
const routes: Routes = [
{
path: '',
component: ProfileStandaloneComponent,
children: [
{
path: '',
redirectTo: 'outputa',
pathMatch: 'full'
},
{
path: 'outputa',
component: ProfileOutputComponent
}
]
}
];
#NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ProfileStandaloneRoutingModule { }
But when I go to url "localhost:4200/profile/123/outputa", my "ProfileOutputComponent" does not get called.
Any idea how to make it work?
Try this.
const routes: Routes = [
{
path: 'outputa',
component: ProfileOutputComponent
];
I have a few components that are all under account.
Username
Password
Profile
...
I want to have a parent component like how the app-component works, with a <router-outlet></router-outlet>, so that the main html of the parent component never changes but the contents of the <router-outlet></router-outlet>.
How do I go about this?
You can define your component route like
const appRoutes: Routes = [
{ path: '/main', component: appComponent },
{ path: 'login/:id', component: LoginComponent },
{
path: 'users',
component: userListComponent,
data: { title: 'User List' }
},
{ path: '',
redirectTo: '/users',
pathMatch: 'full'
},
{ path: '**', component: PageNotFoundComponent }
];
#NgModule({
imports: [
RouterModule.forRoot(
appRoutes,
{ enableTracing: true } // <-- debugging purposes only
)
// other imports here
],
...
})
export class AppModule { }
then in your appComponent.html
<h1>your html</h1>
<router-outlet></router-outlet>
<h1>your html</h1>
https://angular.io/guide/router
You can use children or loadChildren(For Lazy Loading) concepts.
export const AppRoutes:Routes = [
{path: 'account', component: AccountComponent, children: [
{path: 'login', component: LoginComponent},
{path: 'profile', component: ProfileComponent}
]
In AccountComponent, you can add all common APIs and logic
In AccountComponentTemplate, add <router-outlet></router-outlet>
Use Angular Modularization concept for better maintenance.
Define your routes something like this:
const appRoutes: Routes = [
{ path:"", component: HomeComponent},
{ path:"accounts", component: AccountComponent, children:[
{ path:"user", component: UserComponent},
{ path:"password", component: PasswordComponent},
{ path:"profile", component: ProfileComponent}
]},
];
Define a <router-outlet> at root level as well as at child level. For child you can define it inside AccountComponent.html file.
You can follow something like this, that will help you in achieving what you require.
app.routing.ts
export const AppRoutes: Routes = [{
path: '',
component: PARENTcomponentName1,
children: [
{path: 'PATH1', loadChildren: 'MODULE_PATH'}
//more path
]},
{
path: '',
component: PARENTcomponentName2,
children: [
{path: 'PATH#', loadChildren: 'MODULE_PATH'},
]}}]
In app.module.ts I load 2 lazy modules like this
const appRoutes: Routes = [
{ path: 'anonym', loadChildren: './anonym/anonym.module#AnonymModule' },
{ path: 'user', loadChildren: './user/user.module#UserModule', canActivate: [AuthGuard] }
];
In app.component.html I can write some base html. My question - is there any way to have base html for my UserModule?
I have tried to create user.component.ts and load it like in app.module.ts
import { UserComponent } from './user.component';
#NgModule({
declarations: [UserComponent],
bootstrap: [UserComponent]
});
but it's not show me user.component.html
In your user module define a base route with an empty path, and then define the sub-paths as children.
const ROUTES: Routes = [
{
path: '',
component: UsersComponent,
children: [
{
path: '',
pathMatch: 'full',
redirectTo: 'login'
}, {
path: 'login',
component: LoginComponent
}, {
path: 'logout',
component: LogoutComponent
}
]
}
];
The UsersComponent will now be used as a base component, and if you navigate to just /users it will redirect to the /users/login path.
Make sure your UsersComponent has a template with <router-outlet></router-outlet> so the child routes.
#NgModule({
imports: [
RouterModule.forChild(ROUTES)
],
exports: [
RouterModule
]
})
export class UsersModule {
}