In this tutorial, we will cover how to set up routing in an Angular application to create a single-page application. Routing allows users to navigate between pages without a full page reload, providing a more seamless and responsive user experience. We will use a real-world demo application called My Music Library to illustrate how to implement routing in Angular.
The My Music Library application will have multiple pages, each displaying different details about an album. Implementing routing will allow users to navigate between these pages and view different album details without the need for a full page reload. This tutorial will cover the challenges faced when creating a single-page application, such as maintaining application state and providing a smooth user experience, and how to overcome these challenges using Angular routing.
Prerequisites
Before we begin, you should have the following installed on your machine:
Understanding Routing in Angular
Routing is the process of navigating between pages or views in an application. In Angular, routing is used to create a single-page application (SPA) where the content is loaded dynamically without refreshing the page.
Routing in Angular and its purpose.
Routing in Angular is the mechanism used to navigate between different components and views within a single-page application. It allows us to define different URLs for different components, and when the user navigates to a particular URL, the corresponding component is displayed without reloading the page. This provides a seamless user experience and improves the performance of the application.
Types of routing in Angular
There are two types of routing in Angular: Client-side routing and server-side routing.
Client-side routing: Client-side routing is the most common type of routing in Angular. In client-side routing, the routing logic is handled by the Angular router in the browser, and the server only serves the initial HTML page. When the user clicks a link or enters a URL, the Angular router intercepts the request and loads the corresponding component into the view without refreshing the page.
Server-side routing: Server-side routing is less common in Angular, but it's still an important concept to understand. In server-side routing, the routing logic is handled by the server, which generates the HTML for each page and sends it to the browser. When the user clicks a link or enters a URL, the server generates a new HTML page and sends it back to the browser. This approach is useful for applications with a lot of dynamic content or for SEO optimization.
How does routing work in a single-page application?
In a single-page application, all the content is loaded dynamically, and the URL is used to navigate between different components and views. When the user clicks a link or enters a URL, the Angular router intercepts the request and matches it to a route defined in the application. Once a matching route is found, the corresponding component is loaded into the view, and the URL is updated to reflect the new state of the application. The user can then navigate back and forth between different components by clicking links or using the browser's back and forward buttons, and the content is loaded dynamically without reloading the page.
Routing in Angular is a powerful and flexible feature that allows developers to create rich and interactive single-page applications with ease. By understanding the concepts and principles of routing, you can create applications that provide a seamless and engaging user experience.
Setting up Angular Routing
To begin, let's use the Angular CLI to create a new Angular application. Run the command below in your terminal or command prompt:
ng new my-music-library
When you run the ng new command to create a new Angular application, you will be prompted with a series of questions to configure the project. Here's a breakdown of the prompts and the recommended selections:
Would you like to add Angular routing? (y/N) - Answer y to add Angular routing to your application. This will generate a separate routing module that you can use to define your application routes.
Which stylesheet format would you like to use? (Use arrow keys) - Use the arrow keys to select your preferred stylesheet format. The default is CSS, but you can also choose Sass, SCSS, Less, or Stylus.
After the selections, the command will create a new Angular application called my-music-library
.
Next, change directory into the project folder by running the command below:
cd my-music-library
Creating Multiple Routes in Angular
Let's define some routes for our My Music Library application. We will have two main views: a list of albums and a detail view for each album. To define these routes, replace the contents of the src/app/app-routing.module.ts
file with the following code:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AlbumListComponent } from './album-list/album-list.component';
import { AlbumDetailComponent } from './album-detail/album-detail.component';
const routes: Routes = [
{ path: '', redirectTo: '/albums', pathMatch: 'full' },
{ path: 'albums', component: AlbumListComponent },
{ path: 'albums/:id', component: AlbumDetailComponent },
{ path: '**', redirectTo: '/albums' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
This code imports the AlbumListComponent
and AlbumDetailComponent
and defines three routes:
- The empty path redirects to the
/albums
path. - The
/albums
path loads the AlbumListComponent. - The
/albums/:id
path loads the AlbumDetailComponent with the corresponding album ID. - The
**
path redirects to the/albums
path if any other path is requested.
Creating Components for the Routes
We also need to create the AlbumListComponent
and AlbumDetailComponent
that we referenced in the routes. Run the following command to generate the components:
ng generate component album-list
ng generate component album-detail
This will generate two new components in the src/app
directory called album-list
and album-detail
. Open the src/app/album-list/album-list.component.ts
file and replace the contents with the following code:
import { Component, OnInit } from '@angular/core'
import { HttpClient } from '@angular/common/http'
@Component({
selector: 'app-album-list',
templateUrl: './album-list.component.html',
styleUrls: ['./album-list.component.css'],
})
export class AlbumListComponent implements OnInit {
albums: any[] = []
constructor(private http: HttpClient) {}
ngOnInit() {
this.http.get<any[]>('/assets/albums.json').subscribe((albums) => {
this.albums = albums
console.log(this.albums)
})
}
}
This code defines the AlbumListComponent
as a TypeScript class that implements the OnInit interface. It also imports the HttpClient service from @angular/common/http module
, which allows the component to make HTTP requests.
The ngOnInit
method is overridden to load the data for the component. In this case, the component makes an HTTP GET request to the assets/albums.json
file to retrieve a list of albums in JSON format. The subscribe method is used to handle the response and assign the data to the albums property of the component.
Now update the app.module.ts file to import the HttpClientModule
in your app module and add it to the imports array.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AlbumListComponent } from './album-list/album-list.component';
import { AlbumDetailComponent } from './album-detail/album-detail.component';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent,
AlbumListComponent,
AlbumDetailComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Next, open the src/app/album-detail/album-detail.component.ts
file and replace the contents with the following code:
import { Component, OnInit } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { HttpClient } from '@angular/common/http'
@Component({
selector: 'app-album-detail',
templateUrl: './album-detail.component.html',
styleUrls: ['./album-detail.component.css'],
})
export class AlbumDetailComponent implements OnInit {
albumId!: number
album: any
musicList: any[] = []
constructor(private route: ActivatedRoute, private http: HttpClient) {}
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id')
if (id !== null) {
this.albumId = +id
this.http.get<any[]>('/assets/albums.json').subscribe((albums) => {
this.album = albums.find((album) => album.id === this.albumId)
this.musicList = this.album.musicList
console.log(this.albumId,this.album)
})
}
}
}
This updated code defines the AlbumDetailComponent
as a TypeScript class that injects both the ActivatedRoute
service and the HttpClient
service. The ActivatedRoute service is used to get the album ID from the URL parameters, while the HttpClient
service is used to retrieve the album and music list details from the albums.json
file.
The ngOnInit
method first uses the snapshot method of the ActivatedRoute
service to retrieve the album ID from the URL. It then checks if the ID is not null before casting it to a number and assigning it to the albumId
property.
After that, the component subscribes to the HttpClient
service's get method to retrieve the albums.json
file. The subscribe
method takes a callback function that receives an array of albums as a parameter. The find method is used to filter and return the album object that matches the albumId. Once the album is found, its musicList
property is assigned to the musicList
property of the component.
This approach avoids the need for a resolver, as the data is fetched directly from the albums.json
file. However, it is worth noting that this approach is less scalable than using a resolver, as the entire albums.json
file will be fetched each time the component is loaded.
Now create the albums.json
file in the assets
directory and add the code below:
[
{
"id": 1,
"title": "Thriller",
"artist": "Michael Jackson",
"year": 1982,
"genre": "Pop"
},
{
"id": 2,
"title": "Abbey Road",
"artist": "The Beatles",
"year": 1969,
"genre": "Rock"
},
{
"id": 3,
"title": "The Dark Side of the Moon",
"artist": "Pink Floyd",
"year": 1973,
"genre": "Progressive Rock"
}
]
Then add src/assets/albums.json
to the assets array in the angular.json
file:
...
"assets": [
"src/favicon.ico",
"src/assets",
"src/assets/albums.json"
],
...
Creating Templates for the Components
Next, we need to create the HTML templates for our components. Open the src/app/album-list/album-list.component.html
file and replace the contents with the following code:
<h1>Album List</h1>
<div *ngFor="let album of albums">
<h2>{{ album.title }}</h2>
<p>Artist: {{ album.artist }}</p>
<p>Year: {{ album.year }}</p>
<p>Genre: {{ album.genre }}</p>
<a [routerLink]="['/albums', album.id]">View details</a>
</div>
This code defines the HTML template for the AlbumListComponent
. The code uses Angular's built-in structural directive ngFor
to loop through the albums array and display the details of each album.
For each album, it displays its title
, artist
, year
, and genre
. It also creates a link using the routerLink
directive, which allows the user to navigate to the AlbumDetailComponent
to view the album's details.
The link is created using an array, where the first element is the route to the AlbumDetailComponent
and the second element is the id
of the album being displayed. This array is passed to the routerLink
directive using property binding syntax [routerLink]
.
Similarly, open the src/app/album-detail/album-detail.component.html
file and replace the contents with the following code:
<h2>Album Details</h2>
<div *ngIf="album">
<h3>{{ album.title }}</h3>
<p>Artist: {{ album.artist }}</p>
<p>Year: {{ album.year }}</p>
<p>Genre: {{ album.genre }}</p>
</div>
This code defines the layout for the AlbumDetailComponent
view. It includes an h2
heading that says Album Details
and two div elements. The first div element uses *ngIf
to only display its contents if album
is defined. It displays information about the album
, including its title
, artist
, year
, and genre
.
The second div element also uses *ngIf
to only display its contents if musicList
has at least one item. It displays a subheading "Songs" and a list of songs using *ngFor
to loop through each song and display its title
and duration
.
Adding Navigation Links
Finally, let's add some navigation links to our application. Open the src/app/app.component.html
file and replace the contents with the following code:
<h1>My Music Library</h1>
<nav>
<a routerLink="/albums">Albums</a>
</nav>
<router-outlet></router-outlet>
This code defines a heading for the application, a navigation link that points to the /albums
path, and a element that displays the component for the current route.
Running the Application
To run the "My Music Library" application, open your terminal or command prompt and run the following command:
ng serve
This will compile and serve the Angular application at http://localhost:4200/
. Navigate to this URL in your web browser to see the application in action.
So when you click on any of the links, you'll be redirected to the details page.
Conclusion
In this tutorial, we learned how to set up routing in an Angular application to create a single-page application. We used a real-world demo application called My Music Library to illustrate this process. We defined multiple routes for the application and created components and templates for each route. Finally, we added navigation links to the application and ran it to see the results. The code for this tutorial is available here on my GitHub repository.
Top comments (2)
Hey friend, how are you?!
Nice article! When using code blocks we can pass the "type" of code as a parameter, see:
Thanks for that oversight