This tutorial on Routing in Angular 8 app is in continuation of our Angular 8 Tutorial Series and if you have not read the previous parts of the tutorial, it is recommended that you go through them first.
Navigation is at the core of modern web applications. In the digital era most web apps can easily grow from a few hundred to thousands of web pages created dynamically and effective routing is the key to success in such scenarios. In this tutorial , we'll learn how we can add routing to our single page apps written using Angular 8. To achieve our objective , we'll add routing to our InventionsHub
app.
In order to add routing and navigation mechanism to our InventionsHub app , we'll do the following ::
Add new fields details
and id
to the class Invention . Open the file inventions.class.ts
and add the following code to it:
// inventions.class.ts
// add a new class
// add id and details field to the class
export class Invention {
id : number ;
details : String ;
name : String ;
inventor : String ;
year : String ;
}
Update inventions service file inventions.service.ts
and make it resemble the following:
// inventions.service.ts
import { Injectable } from '@angular/core';
import { Invention } from './inventions.class';
@Injectable()
export class InventionsService {
// updated the mock data about inventions to reflect id and details parameters
rawInventions : Invention[] = [
{
id : 1 ,
name : 'Java',
inventor : 'James Ghosling',
year : '1995' ,
details : 'java is an object oriented language '
} ,
{
id : 2 ,
name : 'Python',
inventor : 'Guido van Rosum',
year: '1991' ,
details: 'python is simple yet powerful scripting language '
} ,
{
id : 3 ,
name : 'C++',
inventor : 'Bjarne Stroustrup',
year : '1983' ,
details : ' C++ is the language if you want to make things run faster '
}
]
constructor() {
}
getInventions() : Invention[] {
return this.rawInventions;
}
// added a new method to fetch an invention based on its id
inventionDetails( id ) : Invention {
for ( var i = 0 ; i < this.rawInventions.length ; i++ ) {
if ( this.rawInventions[i].id == id ) {
return this.rawInventions[i];
}
}
return null;
}
}
Now to show details of an invention , lets add a new angular component called details component using the following command:
ng g component details
details.component.ts
and add the following code to it:
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { InventionsService } from '../inventions/inventions.service';
import { Invention } from '../inventions/inventions.class';
@Component({
selector: 'app-details',
templateUrl: './details.component.html',
styleUrls: ['./details.component.css']
})
export class DetailsComponent implements OnInit {
id : string;
invention : Invention;
constructor(
private route: ActivatedRoute,
private router: Router ,
private service : InventionsService
) {
}
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
this.invention = this.service.inventionDetails(+this.id);
}
initialize() {
}
}
details.component.html
to make it look like the following::
<div class="container">
<h2> Details </h2>
<b> Id : </b> {{ invention.id }} <br>
<b> Name : </b> {{ invention.name }} <br>
<b> Inventor : </b> {{ invention.inventor }} <br>
<b> Details : </b> {{ invention.details }} <br>
</div>
inventions.component.ts
and make the changes as shown below:
// inventions.component.ts
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { Invention } from './inventions.class';
import { InventionsService } from './inventions.service';
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-inventions',
templateUrl: './inventions.component.html',
styleUrls: ['./inventions.component.css'] ,
providers: []
})
export class InventionsComponent implements OnInit {
nameModel : String;
inventorModel : String;
yearModel : String;
detailsModel : String;
inventions : Invention[];
totalInventions : number;
constructor(
private inventionsService : InventionsService ,
private router: Router
) {
this.nameModel = '';
this.inventorModel = '';
this.yearModel = '';
this.detailsModel = '';
// consuming the service method getInventions() to fetch default inventions
this.inventions = inventionsService.getInventions();
this.totalInventions = this.inventions.length;
}
ngOnInit() {
}
createInvention(){
this.totalInventions += 1;
let newInvention : Invention = {
id : this.getId(),
name: this.nameModel ,
inventor : this.inventorModel ,
year : this.yearModel ,
details : this.detailsModel
};
this.inventions.push( newInvention );
this.nameModel = this.yearModel = this.inventorModel = '';
}
details( id ) {
this.router.navigate(['/details' , id ]);
}
getId() {
return this.totalInventions ;
}
}
<!-- bind data using curly braces to the data in app.component.ts -->
<!-- comment our the data related to single invention we don't need it because
we're using array now -->
<!--
<h2> {{ invention.name }} </h2>
<h3> {{ invention.inventor }} </h3>
<h3> {{ invention.year }} </h3>
-->
<!-- use *ngFor to iterate through array of inventions and print information about them -->
<div *ngFor="let i of inventions">
<div class="invention">
<span> <b> Name: </b> {{ i.name }} || </span>
<span> <b> Inventor: </b> {{ i.inventor }} || </span>
<span> <b> Year: </b> {{ i.year }} </span>
<span> <button class="btn btn-primary" (click)="details(i.id)"> details </button> </span>
</div>
</div>
<!-- add new inventions -->
<hr>
<!-- Let the user enter information and display the same side by side -->
<!-- <label> {{ nameModel }} </label> -->
<div class="invention-creator">
<div>
<input [(ngModel)]="nameModel" placeholder="enter name" class="form-control">
</div>
<hr>
<!-- <label> {{ inventorModel }} </label> -->
<div>
<input type="text" [(ngModel)]="inventorModel" placeholder="enter inventor " class="form-control">
</div>
<hr>
<!-- <label> {{ yearModel }} </label> -->
<div>
<input [(ngModel)]="yearModel" placeholder="year" class="form-control">
</div>
<hr>
<div>
<textarea type="textarea" rows="4" cols="20" [(ngModel)]="detailsModel" placeholder="details" class="form-control">
</textarea>
</div>
<br>
<!-- call the createInvention() function from component on click of button -->
<!-- note the use of parenthesis for the click event -->
<button class="btn btn-primary" (click)="createInvention()"> create invention </button>
</div>
Now open the file app.module.ts
and add the routing imports and configuration as following:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { InventionsComponent } from './inventions/inventions.component';
import { InventionsService } from './inventions/inventions.service';
import { RouterModule } from '@angular/router';
import { DetailsComponent } from './details/details.component';
@NgModule({
declarations: [
AppComponent,
InventionsComponent,
DetailsComponent
],
imports: [
RouterModule.forRoot([
{
path: '',
redirectTo: 'inventions',
pathMatch: 'full'
},
{
path: 'inventions',
component: InventionsComponent
} ,
{
path: 'details/:id' ,
component: DetailsComponent
}
]),
BrowserModule ,
FormsModule
],
providers: [ InventionsService ],
bootstrap: [AppComponent]
})
export class AppModule { }
Right from beginning we've been using app.component as a container, and now it's clearly visible why we did that. Our app.component
will act as a container component and this is where we'll add outlets for our routes.
Open the file app.component.html
and edit it to resemble the following:
<!-- app.component.html -->
<div class="container">
<div style="text-align:center">
<h1>
Welcome to {{title}}!!
</h1>
</div>
||
<a routerLink="/inventions"> Inventions </a> ||
<hr>
<!-- <app-inventions> </app-inventions> -->
<router-outlet></router-outlet>
</div>
http://localhost:4200
. Following are the screenshots taken from our InventionsHub app.
Let's see what we learned in this tutorial on navigation and routing in Angular 8 apps ::