Skip to content

Instantly share code, notes, and snippets.

@narainsagar
Last active June 1, 2018 23:30
Show Gist options
  • Save narainsagar/5db7ea154931d135c82e54df97cb4c27 to your computer and use it in GitHub Desktop.
Save narainsagar/5db7ea154931d135c82e54df97cb4c27 to your computer and use it in GitHub Desktop.
Code snippets for talk on Angular4 Advanced Routing, slides are here: https://goo.gl/N8DneM

Basic Routing

import { ChildRoutes } from './child.routes';

const APP_ROUTES: Routes = [
    { path: '', redirectTo: 'login', pathMatch: 'full' },
    { path: 'login', component: LoginComponent },
    { path: 'register', component: RegisterComponent },
    { path: 'dashboard', component: DashboardComponent },
    { path: 'my-children', children: ChildRoutes },
    { path: '**',    component: PageNotFoundComponent },
];

RouterModule.forRoot(
    APP_ROUTES,
    { enableTracing: true } // <-- debugging purposes only
)

Children Routes

[
  {
    path: 'tasks',
    children: [
      { path: '', redirectTo: 'task1', pathMatch: 'full' },
      { path: 'task1', component: Task1Component },
      { path: 'task2', component: Task2Component },
      { path: 'task3', component: Task3Component }
    ]
  },
];

Route Guards

CanActivate & CanActivateChild & CanDeactivate

// auth.service.ts
@Injectable()
class AuthService {
  isLoggedIn(): boolean {
    let _isLoggedIn = false;
    // check if user is logged in or not.
    // _isLoggedIn = true;
    return _isLoggedIn;
  }
}
// auth.guard.ts
@Injectable()
export class AuthGuard implements CanActivate {
    constructor(private authService: AuthService) {}

    canActivate(route: ActivatedRouteSnapshot,
      state: RouterStateSnapshot): boolean {
        if (this.authService.isLoggedIn()) {
          return true;
        } else {
          // redirect to /login or /404 page.
          // this.router.navigate(['/login']);
          window.alert(`You don't have permission to view this page`);
          return false;
        }
    }
}
// auth-child.guard.ts
@Injectable()
export class AuthChildGuard implements CanActivateChild {
    constructor(private authService: AuthService,
      private authGuard: AuthGuard) {}

    canActivateChild(route: ActivatedRouteSnapshot,
      state: RouterStateSnapshot): boolean {
        return this.authGuard.canActivate(route, state);
    }
}
// search.component.ts

canDeactivate() {
  return this.results.length > 0;
}

// unsearched-term.guard.ts
class UnsearchedTermGuard implements CanDeactivate<SearchComponent> { 
  canDeactivate(component: SearchComponent, 
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
    return component.canDeactivate() || window.confirm('Are you sure?');
  }
}
// app.routes.ts
[
  {
    path: 'search',
    component: SearchComponent,
    canDeactivate: [ UnsearchedTermGuard ]
  },
  {
    path: 'tasks',
    component: TasksComponent,
    canActivate: [ AuthGuard, AuthChildGuard ],
    children: [
      { path: '', redirectTo: 'task1', pathMatch: 'full' },
      { path: 'task1', component: Task1Component },
      { path: 'task2', component: Task2Component },
      { path: 'task3', component: Task3Component }
    ]
  },
];
// app.module.ts
@NgModule({
  providers: [
    AuthGuard,
    AuthChildGuard,
    UnsearchedTermGuard
  ]
})

CanLoad

// can-load.guard.ts
@Injectable()
class CanLoadGuard implements CanLoad {
  canLoad(route: Route): Observable<boolean>|Promise<boolean>|boolean {
    return true;
  }
}

// app.module.ts
@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: 'tasks',
        component: TasksComponent,
        canLoad: [ CanLoadGuard ],
        loadChildren: './tasks/tasks.module#TasksModule'
      },
    ])
  ],
  providers: [ CanLoadGuard ],
})

// app.module.ts (i.e., `canLoad` as signature)
@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: 'tasks',
        component: TasksComponent,
        canLoad: [ 'CanLoadGuard' ],
        loadChildren: './tasks/tasks.module#TasksModule'
      }
    ])
  ],
  providers: [
    {
      provide: 'CanLoadGuard',
      useValue: (route: Route) => true
    }
  ]
})

Resolvers

// backend.service.ts
@Injectable()
class BackendService {
  fetchTeam(id: string) {
    return 'someTeam';
  }
}
// team-resolver.service.ts
@Injectable()
class TeamResolverService implements Resolve<Team> {
  constructor(private backendService: BackendService) {}
 
  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<any>|Promise<any>|any {
    return this.backendService.fetchTeam(route.params.id);
  }
}
// team.component.ts
@Component()
export class TeamComponent implements OnInit {
  team;
  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.team = this.route.snapshot.data['team'];
  }
}
// app.module.ts
@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: 'team/:id',
        component: TeamComponent,
        resolve: {
          team: TeamResolverService
        }
      }
    ])
  ],
  providers: [TeamResolverService]
})
class AppModule {}
@NgModule({
  imports: [
    RouterModule.forRoot([{
      path: 'team/:id',
      component: TeamCmp,
      resolve: {
        team: 'teamResolver'
      }
    }])
  ],
  providers: [{
    provide: 'teamResolver',
    useValue: (
      route: ActivatedRouteSnapshot,
      state: RouterStateSnapshot
    ) => 'team'
  }]
})
class AppModule {}

Lazy Loading Modules

// app.routes.ts
[
    { path: '', redirectTo: '/tasks', pathMatch: 'full' },
    { path: 'about', component: AboutComponent },
    { path: 'tasks', loadChildren: './tasks/tasks.module#TasksModule' },
    { path: 'users', loadChildren: './users/users.module#UsersModule' },
    { path: '**',    component: PageNotFoundComponent },
]

Preloading

RouterModule.forRoot(
  APP_ROUTES, 
  { preloadingStrategy: PreloadAllModules }
)

Custom Preloading Strategy

// app.routes.ts
[
  {
    path: 'moduleA',
    loadChildren: './moduleA.module#moduleA',
    data: { preload: true }
  },
  {
    path: 'moduleB',
    loadChildren: './moduleB.module#moduleB'
  }
];
// custom-preloading-strategy.ts
export class CustomPreloadingStrategy implements PreloadingStrategy {
  // preload selected modules list.
  preload(route: Route, load: Function): Observable<any> {
    return route.data && route.data.preload ? load() : of(null);
  }
}
// app.module.ts
@NgModule({
  bootstrap: [ AppComponent ],
  providers: [ CustomPreloadingStrategy ],
  imports: [
    RouterModule.forRoot(
      ROUTES, 
      { preloadingStrategy: CustomPreloadingStrategy }
    )
  ]
})
class AppModule {}

License

MIT - Narain Sagar narainmenghwar@gmail.com

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment