Routing in Angular
Angular has a built-in router. When initializing a new project, the CLI asks if it should be included or not. If we opted for “No” initially, we can add routing module manually:
We can also configure routing in the
The selected component will be rendered as a child of
AppComponent. We need to
specify the exact placement of that component:
The routes array should generally contain a wildcard route that handles all bad links. Usually, it would redirect the user to some 404 page.
Paths of routes defined in the array are prefix paths by default. It means
that Angular will match it whenever the beginning of browser’s URL matches the
route’s path. If we want the route to be selected only when the whole URL is
matched (without the host though), we should add the
pathMatch: 'full' option.
Usually, we do not define routes directly in
app.module.ts. Instead, we’d
create a separate module file
app-routing.module.ts with the routing setup
inside of it.
app.module file gets simplified:
We can also split routes per feature.
Navigation in HTML
With routing in place, we don’t want to navigate between different pages in our
app with traditional
<a href="/whatever">Whatever</a>. Clicking such a link
will work and the user will be taken to the right component (if the
route was configured), but it comes with a huge issue - the whole application
will actually be reloaded from the server again. The app’s state will be lost,
and it will be slow. Instead of that, we want the Angular Router to handle the
navigation, making it an in-app navigation rather than a browser-based
navigation. Here’s how
<a> elements should look like:
The link above is applied to the host of the page. If we didn’t include the
home segment would be applied to the currently open page. It works
differently in Programmatic Navigation!
In order to have visual indication on the currently visited menu element, we
would normally attach some CSS class to that active element. Angular comes with
a helper directive that does that automatically -
The element that has the directive on it will have the “active” class attached
to it when the link is active. The directive can be attached on the
<a> or on
some element that wraps it, like in the example above.
Navigation in TypeScript
Router is accessible via TS as well.
The path that we navigate to is (by default) relative to the root.
Having or not having slash in the beginning does not change anything (it does
matter with routerLink)! We can change the path that
will be executed in relation to with
relativeTo. For example, we could pass to
it the currently activated route (
Route’s path can have parameters. In the code example at the top of this page,
movies/:movieId is an example of that.
movieId is a parameter, and the
MovieComponent will receive it.
We can get information about currently loaded route by injecting
ActivatedRoute. It contains various metadata about the loaded path, e.g. the
The parameters may also be subscribed to via an
this.route.params. It might be useful when we plan to link from some site to
itself with different parameters. In such a case, Angular will not reload the
whole component for optimization. Instead, only the
We can also make use of query parameters. To attach them to links on our page, we do it as follows:
Here’s how we add query params from TS:
Here’s how we can read query params from TS by injecting
Similarly to path parameters, we can also subscribe to
Preserving Query Params
When we’re on some page with some query params in the URL, by default these query params will be removed when we navigate to another page. If we don’t want that, we can do it the following way:
merge handling merges together existing query params and those that we
might want to add (by having
Similarly, we can attach fragment (
#fragment) to link we navigate to:
Here’s how we add fragment from TS:
Here’s how we can read fragment from TS by injecting
Similarly to path parameters, we can also subscribe to
Routes can have some static data defined. This way, the same route can be reused
multiple times. For example, we could have a generic
displays different message depending on the kind of error. Such a component
could look like this:
We can set the static value(s) in the routes collection:
Nested Routing allows us to have multiple routing outlets, one within another. We could have a main menu with each entry of it loading a different submenu. Then, each submenu would have a list of links that load a different content.
First, we need to set up our routes properly:
In the example above,
/:movieId is a nested route. The full path (without
host) to it is
The next thing to do is to place an outlet where the
MovieComponent will be
rendered. We should place it somewhere within
With this setup, when navigating to
/movies/<id>, the following will happen:
MoviesComponentwill be rendered in the
MovieComponentwill be rendered in the
The setup could be more complex, having multiple children under the
path, or by having more levels of nesting.
Routes can be protected by Guards. The user may be either allowed or disallowed to enter some content. It could be due to them being (un)authorized in some way.
Guards are services and we normally store them in
Here’s a simple example:
The guard needs to implement
canActivate method should
return one of:
bool | UrlTree
Observable<bool | UrlTree>
Promise<bool | UrlTree>
We can route users to some other page in the guard, most likely when the
condition is not satisfied. We use the
UrlTree for that - it’s one of the
types that may be returned from guards. Here’s how we’d return it:
router is an instance of a
The route should be enabled for selected endpoints in the routes definition:
/users endpoint is protected by our guard. If we applied the guard to the
/movies route, the child of it would also use it.
Similarly to checking if a user can enter some route, we can also check if they should be able to leave it. This is to protect users from unintentionally leaving half-done form, forgetting to save their work, etc.
Setting this up is a little bit more involved than using
That’s because the guard will most likely need some input from the component
that we’re leaving to know if the user should be able to leave. The component
could have some
isWorkSaved variable, but the guard cannot reach it - it’s a
separate class after all. We can solve this problem using generics.
Here’s an example:
Next piece is the actual component’s code. The component needs to
To use the new guard, we need to enable it in the routes collection:
When a given component needs some external data to be loaded before it can be displayed, custom Resolvers can be used.
Here’s an example of such a resolver:
To use the resolver, we attach it to the route that needs it:
Here’s how we can access the result of resolver’s work in the
We subscribe to the result, because the resulting data could change when we reload the component (Angular will not reload the whole component for performance reasons).
The result is placed in
this.route.data object under the key that we used in
the route definition’s
resolve section (
movie in this case). The
object was also used in the Static Data.
Lazy Loading is described in the Modules section.