The Angular Router + Common Tasks

by Stephen Fluin

2018-02-12

The Angular Router + Common Tasks
The Angular router is one of the first ways that you can take state from the user, and use it to make rendering choices in your application.
To put it simply, you have a path in the URL bar which the router translates into a set of components to render, and then passes in any parameters to those components.
Here's an example routing config:
export const routeConfig: Routes = [
    { path: '', component: HomeComponent, data: { title: 'fluin.io', page: 'home' } },
    {
        path: 'blog', data: { title: false, page: 'blog'  }, component: BlogComponent, children: [
            { path: '', component: BlogPostComponent },
            { path: ':id', component: BlogPostComponent },
        ]
    },
    { path: 'bio', component: BioComponent, data: { title: 'About Stephen Fluin' } },
    { path: 'projects', component: ProjectsComponent, data: { title: 'Projects' } },
    { path: 'admin', loadChildren: 'app/admin/admin.module#AdminModule' },
    { path: '404', component: NotFoundComponent},
    { path: '**', component: Send404Component },
];

Hierarchy

You can nest routes. Nested routes end up being concatenated (e.g. /blog/:32) selects the blog path, and renders the BlogPostComponent.
Modules and components themselves can nest multiple Router Outlets, resulting in being able to supply a template such as admin that can be used for multiple admin routes.
This is most commonly done with loadChildren where you point to another module in your application, which then gets split into a separate chunk as part of the build process. This chunk and all of its dependencies are only loaded when you navigate to that route. This means your application gets smaller and faster for your users.

Navigation Events

I love tapping into navigation events for several common patterns. Let's take a look at the code in my constructor in my root component.
router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe((n: NavigationEnd) => {
    let pageTitle = router.routerState.snapshot.root.children[0].data['title'];
    if (pageTitle) {
        title.setTitle(pageTitle);
    } else if (pageTitle !== false) {
        title.setTitle('fluin.io');
    }
    window.scrollTo(0, 0);
    ga('send', 'pageview', n.urlAfterRedirects);
});

In this constructor, I listen for all NavigationEnd events, and then do several things:
  1. I set the page title based on the data.title from my route configuration.
  2. I scroll the page to the top (hopefully the Angular team will make this smarter and automatic some day)
  3. I send an analytics event to Google Analytics.