This tutorial is out of date and no longer maintained.
We have been so eager here at Scotch to create a comprehensive guide on Angular 2 Component Router. Now that a reliable version (v3) has been released, it’s a good time then to discuss Component Router.
This article will serve as a guide to implementing routing in Angular 2 with a fully fleshed out example touching major aspects of routing including bootstrapping, configuration, parameterized routes, protecting routes, etc. In the past, we’ve looked at routing in Angular 1.x with ngRoute and UI-Router.
Take a look at what we’ll be building today:
View on Scotch Angular Router on plnkr
Angular 2 uses TypeScript, so if you need a refresher on that, take a look at why TypeScript is your friend and our TypeScript tutorial series.
Before we get started and to save us some setup time, clone the Angular 2 QuickStart then we can build on top of that.
The seed already has end-to-end tools to enable you to start building Angular 2 apps. It also comes with all Angular 2 dependencies including angular/router
so we can just pull the packages from npm:
We are more concerned with the app
folder of our new project which is simply:
|---app
|-----main.ts # Bootstrapper
|-----app.component.ts # Base Component
|-----app.component.spec.ts # Base Test File
Note: Testing is out of scope for this tutorial so we won’t be making use of app.component.spec.ts
, but we’ll be writing up an article on Angular 2 testing shortly.
Routing requires a lot more files than the above so we will re-structure and organize our app units in folders:
We are not so interested in how the app looks but it won’t hurt to make our app look prettier than what the quickstart offers.
Material Design and Angular are very good friends so we could go ahead to make use of Material Design Lite (MDL). Grab MDL with npm:
Replace <link rel="stylesheet" href="styles.css">
in ./index.html
with:
You can then add some custom styles in the styles.css
:
Let’s get started with configuring a basic route and see how that goes. app.routes.ts
holds the base route configuration and it does not exist yet so we need to create that now:
We import what we need for the base route configuration from @angular/router
and also some components we have yet to create.
We then define an array of routes which is of type Routes
then use RouterModule.forRoot
to export the routes so they can be injected in our application when bootstrapping. The above configuration is basically what it takes to define routes in Angular 2.
The routes config file imports some components that we need to create. For now, we just create them and flesh them out with minimal content, then we can build on them while we move on.
Just a basic Angular 2 component with a decorator and a component class.
Note: Learn more with this tutorial.
Before we bootstrap the app, we need to assemble our imports, providers, and declaration using NgModule
so they can be available application-wide. This is a new feature with saves the hustle of managing dependencies in complex projects and makes features (collection of components, services, pipes, and directives that offers a single goal) composable.
We are doing great work already in configuring our application. It’s time to bootstrap our application in ./app/main.ts
with the configured routes. Open main.ts
and update with:
What this code does is bootstrap our App while injecting our root module during the bootstrap process.
The question is, where is our App? It is yet to be created and we will do that right now:
By configuring and providing the routes using RouterModule
, we also get some important directives including RouterOutlet
(used as router-outlet
) to load route templates and RouterLink
to help with navigation.
The RouterLink directive substitutes the normal href
property and makes it easier to work with route links in Angular 2. It has the following syntax:
The RouterOutlet directive is used to display views for a given route. This is where templates of specific routes are loaded while we navigate:
Angular makes it easy to make our SPA route URLs look indistinguishable form sever-served URLs. All we need to do is set base URL in the index.html
:
Let’s see how far we have gone by running the app:
We do not have an index route (/
) and that will throw errors to the console. Ignore it (will fix that) and navigate to /cats
or /dogs
:
Yes, we have a functional route, but we all know that real-life applications require a bit more than a simple route. Real apps have index/home page routes for:
Let’s take some time and have a look at some of these routing features.
The first and most important is to fix our index route. I can’t think of any relevant information to put in the index route so what we can do is redirect to /dogs
once the index route is hit.
We just successfully killed two birds with one stone. We have an index route and we have also seen how we can redirect to another route. If you prefer to have a component to the index route, configure as follows:
When making a redirect it is important to tell the router how to match the URL. There are two options for that - full
or prefix
. full
matches the URL as it is while prefix
matches URL prefixed with the redirect path.
This is a good time to add more features to the demo app by fetching the list of pets from a remote server and retrieving each pet’s details with their ID. This will give us a chance to see how route parameters work.
It’s a good practice to isolate heavy tasks from our controllers using services. A service is a data class provider that makes a request (not necessarily an HTTP call) for data when a component needs to make use of it:
HTTP and DI are beyond the scope of this article (though coming soon) but a little explanation of what is going on won’t cause us harm.
The class is decorated with an @Injectable
decorator which tells Angular that this class is meant to be used as a provider to other components. JSONP rather than HTTP is going to be used to make API requests because of CORS so we inject the service into PetService
.
The class has 3 members - a private property that just holds the base URL of the Petfinder API, a method to retrieve the list of pets based on the type, and another method to get a pet by its ID.
PetService was not built to run on it’s own, rather we need to inject the service into our existing list components:
Note: The trailing .$t
is a result of the API structure and not an Angular thing so you do not have to worry about that.
We are binding an observable type, dogs
to the view and looping through it with the NgFor
directive. The component class extends OnInit
which when its ngOnInit
method is overridden, is called once the component loads.
A VERY important thing to also note is the routerLink
again. This time it does not just point to /dog
but has a parameter added
CatListComponent
looks quite exactly like DogListComponent
so I will leave that to you to complete.
The link from the list components points to a non-existing route. The route’s component is responsible for retrieving specific pet based on an id. The first thing to do before creating these components is to make there routes. Back to the app.routes
:
For modularity, the dog-related routes have been moved to a different file and then we import and add it to the base route using the spread operator. Our dog.routes
now looks like:
There is now a DogDetailsComponent
as you can now see but the component is yet to be created. The component will receive id
parameter form the URL and use the parameter to query the API for a pet:
What is important to keep an eye on is that we are getting the ID form the route URL using ActivatedRoute
. The ID is passed into the PetService
’s findPetById
method to fetch a single pet. It might seem like a lot of work of having to subscribe to route params but there is more to it. Subscribing this way makes it easier to unsubscribe once we exit the component in ngOnDestroy
thereby cutting the risks of memory leak.
Now it’s time to take it as a challenge to complete that of CatDetailsComponent
and CatRoutes
though you can find them in the demo if you get stuck.
Let’s take a look at one more thing we can do with component router
Sometimes we might have sensitive information to protect from certain categories of users that have access to our application. We might not want a random user to create pets, edit pets or delete pets.
Showing them these views when they cannot make use of it does not make sense so the best thing to do is to guard them.
Angular has two guards:
This is how we can make use of the guard:
It’s a class that implements router’s CanActivate
and overrides canActivate
method. What you can do with with the service is supply as array value to canActivate
property of route configuration:
There is room to learn a lot more on Angular Component Router but what we have seen is enough to guide you through what you need to start taking advantage of routing in an Angular 2 application.
More to come from Scotch and Scotch-School on Angular 2, do watch out so you don’t miss.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!