AdminModule

Next, we’ll separate out our Admin module. Following our pattern above, we’ll create src/app/admin/admin.module.ts -

// admin.module.ts import { NgModule } from '@angular/core'; import { SharedModule } from '../shared/shared.module';

import { AdminRoutingModule } from './routing/admin-routing.module'; import { DashboardComponent,

AdminComponent,

CategoriesComponent, TagsComponent,

AdminQuestionsComponent } from './components'; @NgModule({

declarations: [

DashboardComponent,

AdminComponent,

CategoriesComponent, TagsComponent,

AdminQuestionsComponent

],

imports: [

//rwa modules

SharedModule,

AdminRoutingModule

]

})

export class AdminModule { }

The AdminModule will have it’s own routing module - AdminRoutingModule. We’ll move the admin child routes from our main app.route to admin.route -

// admin.route.ts import { Routes, RouterModule } from '@angular/router';

import { DashboardComponent, CategoriesComponent, TagsComponent,

AdminQuestionsComponent, AdminComponent }

from '../components/index';

import { AuthGuard } from '../../core/services'; export const adminRoutes: Routes = [

{

path: '',

component: AdminComponent,

canActivate: [AuthGuard],

canActivateChild: [AuthGuard],

children: [

{

path: '',

pathMatch: 'full',

component: DashboardComponent

},

{

path: 'categories',

component: CategoriesComponent

},

{

path: 'tags',

component: TagsComponent

},

{

path: 'questions',

component: AdminQuestionsComponent

} ]

}

];

admin-routing.module

// admin-routing.module.ts import { NgModule } from '@angular/core';

import { RouterModule } from '@angular/router'; import { adminRoutes } from './admin.route'; @NgModule({

imports: [

RouterModule.forChild(adminRoutes)

]

})

export class AdminRoutingModule { }

We‘ll move our admin components to the admin/components folder. Our DashboardComponent is currently shared between our main home component and admin component. Since, we’d like to have a separate dashboard for admin eventually, I would simply make a copy of Dashboard Component inside admin (instead of putting this in SharedModule and keeping it shared). We’ll have 2 instances of Dashboard with the same functionality for now, but we plan to differentiate them in the near future.

Let’s remove the admin routes from our app.route and replace the root admin route to point to the AdminModule -

// app.route.ts import ...

export const routes: Routes = [

{

path: '',

redirectTo: '/dashboard',

pathMatch: 'full'

},

{

path: 'dashboard',

component: DashboardComponent

},

{

path: 'questions',

component: MyQuestionsComponent,

canActivate: [AuthGuard]

},

{

path: 'question/add',

component: QuestionAddUpdateComponent,

canActivate: [AuthGuard]

},

{

path: 'admin',

loadChildren: 'app/admin/admin.module#AdminModule',

canActivate: [AuthGuard]

}

];

Note the use of loadChildren: ‘app/admin/admin.module#AdminModule’,

And let’s cleanup our app.module -

// app.module.ts imports ...

@NgModule({

declarations: [

AppComponent, DashboardComponent,

QuestionAddUpdateComponent, MyQuestionsComponent

],

imports: [

BrowserModule, //rwa modules

CoreModule,

SharedModule,

RoutingModule,

AdminModule

],

providers: [

],

bootstrap: [AppComponent]

})

export class AppModule { }

Cleanup import references and test it. Complete code for commit.

Lazy-loading AdminModule

The AdminModule is still eager loaded as it’s imported in the AppModule. In order to lazy load the AdminModule, we simply remove it from getting imported in AppModule and remove the import statement in app.module. See the change to app.module here.

In order to test this, you can open Chrome debugger tools and see that a new module is being loaded when you click on “Admin” in the menu for the first time. Undo the change above and test it again. You’ll notice that the admin module is loaded by default and no new module gets loaded when Admin is clicked. Functionally, the two scenarios are exactly the same though.

canLoad Guard

We’re already protecting our Admin feature by checking if the user has permissions in the admin component, but the router might still load the AdminModule.

You can test it out by removing the check for admin role in our App component’s menu. Remove *ngIf=”user?.roles.admin” check from app.component.html and login using a non-admin user. You’ll see that the AdminModule gets loaded (see above note for how to test), even though it get’s redirected back to the home page because of the check in the component.

In order to prevent the AdminComponent from even loading, we can add a canLoad method to our auth-guard component and use this as a guard on the admin route.

Add canLoad to auth-guard.ts -

// auth-guard.ts imports ... @Injectable() export class AuthGuard implements CanActivate, CanActivateChild, CanLoad { ... canLoad(route: Route): boolean {

if (this.authService.isAuthenticated && this.authService.user.roles["admin"])

return true; return false;

}

}

Use the guard in app.route.ts -

Let’s test it again. Commit source here.