How to have a sidenav with router-outlet and a separate login with router-outlet?

Apostrofix picture Apostrofix · Jan 10, 2018 · Viewed 13.8k times · Source

I am trying to implement an app with a login page and then when the user is logged in, there would be a navbar, toolbar and sidenav that have a router-outlet.

Basically, in the app.component.html I have a defined this:

<div *ngIf="isAuthenticated">
    <app-custom-navbar></app-custom-navbar>
    <app-custom-toolbar></app-custom-toolbar>
    <app-custom-sidenav></app-custom-sidenav>
</div>

<router-outlet></router-outlet>

And I have this routing:

const routes: Routes = [
    { path: '', canActivate: [AuthenticationGuard], component: HomeComponent },
    { path: 'login', component: LoginComponent },
    { path: 'data', canActivate: [AuthenticationGuard], component: DataComponent },
    { path: 'projects', canActivate: [AuthenticationGuard], component: ProjectsComponent },
];

So, this works well, if the user isn't authenticated, he gets redirected to /login.

The problem is that when he is authenticated, the sidenav component takes the whole space and then the other components cannot be seen.

Basically this is the problem:

<mat-sidenav-container class="sidenav-container">
  <mat-sidenav>

    <!-- sidenav template... -->

  </mat-sidenav>
  <mat-sidenav-content>

   <!-- how can I put my content here and use routing at the same time ? -->
   <!-- <router-outlet></router-outlet> -->

  </mat-sidenav-content>
</mat-sidenav-container>

I thought about using aux routes, but then the routes are not user friendly. Instead I would like to keep them simple like:

http://mywebsite.com/data
http://mywebsite.com/login
http://mywebsite.com/projects

EDIT: The problem is solved now: Basically, I had to setup the routing properly. I needed to add main routing - e.g. login, logout and default route. And then I added my components as children items under the default route, which in my case is an empty '' path. That way my routes look clean and it looks the way I want it. I am editing my post with a link to a working example.

Here is the url to: stackblitz

Answer

jriver27 picture jriver27 · Jan 10, 2018

You will need two files with Routes. The first file will contain the pages without the navbar/sidebar.

app.routes.ts

import { Routes } from '@angular/router';

export const ROUTES: Routes = [
      {
        path: '', redirectTo: 'login', pathMatch: 'full'
      },
      {
        path: 'myApp', canActivate: [IsAuthorized], loadChildren: './layout/layout.module#LayoutModule'//<- Other routes here
      },
      {
        path: 'login', loadChildren: './login/login.module#LoginModule'
      },
      {
        path: 'error', component: ErrorComponent
      },
      {
        path: '**', component: ErrorComponent
      }
    ];

The Next file will contain the routes to other components or Modules.

layout.routes.ts

import { Routes, RouterModule } from '@angular/router';
import { LayoutComponent } from './layout.component';
const routes: Routes = [
      { path: '', component: LayoutComponent, children: [
        { path: 'admin', loadChildren: '../admin/admin.module#AdminModule'},
        { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
        { path: 'home', loadChildren: '../home/home.module#HomeModule' },
        { path: 'about', loadChildren: '../about/about.module#AboutModule' }
      ]}
    ];
    export const ROUTES = RouterModule.forChild(routes);

layout.module.ts

import { ROUTES } from './layout.routes';
import { NavbarComponent } from './navbar/navbar.component';
import { SidebarComponent } from './sidebar/sidebar.component';

@NgModule({
  imports: [
    ROUTES
  ],
  declarations: [LayoutComponent, SidebarComponent, NavbarComponent
})
export class LayoutModule {
}

Now in your layout.component.html file you will have the following layout.

layout.component.html

<app-custom-navbar></app-custom-navbar>
<app-custom-toolbar></app-custom-toolbar>
<app-custom-sidenav></app-custom-sidenav>
  <router-outlet></router-outlet>

app.module.ts

import { ROUTES } from './app.routes';
...
imports: [
    RouterModule.forRoot(ROUTES, {
      useHash: true,
      preloadingStrategy: PreloadAllModules
    })
  ],
...
export class AppModule { ... }

home.module.ts

export const routes = [
  { path: '', component: HomeComponent, pathMatch: 'full' }
];

NgModule({
  declarations: [
    HomeComponent
  ],
  imports: [
    RouterModule.forChild(routes),
  ]
})
export class HomeModule {
  public static routes = routes;
}

So now you can see that your AppModule will load the first app.routes.ts and take you to the login module. After the user logs in and is authenticated. You can redirect them to 'myApp/home'. This will trigger the HomeModule (that also has routes!) to load the HomeComponent.