Routing and navigation with Angular 18

Updated : 14/06/2024 danny

Routing allows you to manage the URLs or Routes of a Web Application

In this tutorial we will integrate the routing   using the Angular javascript framework version 18.0.2

Angular has the angular@router library.

This will allow us to quickly and easily set up navigation through routing.

Routing avec Angular

How to do it ?

To achieve this routing here is a summary of what we are going to do

  • Before you start
    What is routing or routing?
     
  • Creation of our Angular project
    We will use an existing project containing the essential functionalities.
    The project was generated with Angular CLI.
     
  • Project structure
    Before integrating our modifications, we must choose a structure.
     
  • Project initialization
    Using angular Cli
     
  • Child Routes
    How to manage more complex routes
     
  • Perform the Tests
    Perform unit tests.
    ​​​​​​​
  • Source code
    For those in a hurry, the complete project code is available on Github.

    Just go to the following address
    https://github.com/ganatan/angular-react-routing

Before you start

First an example to try to understand the theory.

2 films interest us or rather interest our children (it's up to you).
So let's use Wikipedia it's fast and it's simple.

And let's see what it looks like.

Angular HTML et Routing Le roi Lion et avengers

A few explanations now.

A website is made up of a multitude of pages.
These pages are written thanks in particular to the HTML language.
HTML stands for HyperText Markup Language .

Hypertext is the technology that will link a page to other pages via hyperlinks .

Routing is the mechanism that allows you to navigate from one page to another in our example.

For example if you type these two url in your browser.


Depending on the movie name indicated in the url, the Wikipedia web application will determine the processing to be performed.
This processing will display the web page corresponding to the requested film (here The_Lion_King or Avengers:_Endgame ).

This is called Routing (literally translated into English as Routing ).

If we had to make a comparison, it's a bit like an air traffic controller or a station master .
Without Routing we no longer know where we are going.

​​​​​​So you will have understood it without routing no web application.
What could give that.

Angular sans routage avec routage


This principle of operation being omnipresent in the use of a website, we must apply it as quickly as possible in any web project.

We will therefore implement this mechanism in our Angular project.


Creating the Angular project

To be able to continue this tutorial we must obviously have certain elements

  • Node.js : The javascript platform
  • Git : The version control software.
  • Angular CLI : The tool provided by Angular.
  • Visual Studio code : A code editor.

You can consult the following tutorial which explains in detail how to do it.


In this tutorial we will use an existing project whose characteristics are

  • Generated with Angular CLI
# Create a demo directory (the name is arbitrary here)
mkdir demo

# Go to this directory
cd demo

# Get the source code on your workstation
git clone https://github.com/ganatan/angular-react-starter

# Go to the directory that was created
cd angular-react-starter
cd angular

# Run the installation of dependencies (or libraries)
npm install

# Run the program
npm run start

# Check how it works by running the command in your browser
http://localhost:4200/

Project structure

The question of the structure of our project arises very quickly.
This structure will condition the modifications that we will make as the project develops.

When creating the project with Angular CLI the structure created by default is the following

Noticed
The environments directory is no longer auto-generated since Angular 17.
I added it manually in the previous Getting Started with Angular tutorial.

|-- src/
    |-- app
    |-- assets
    |-- environments
package.json

Nous allons suivre cette façon de procéder en imaginant les éléments qui pourraient constituer notre projet.

|-- src/
    |-- app
        |-- components
        |-- directives
        |-- mocks
        |-- pages
        |-- pipes
        |-- services
    |-- assets
    |-- environments
package.json


The choice we made is arbitrary, your structure can take any other form.
This choice will nevertheless be followed in the following tutorials.

  • pages/general will group the elements found in all projects.
  • pages/application will group application-specific elements.

To create a new project, simply copy the base project and adapt modules/application to our needs.

|-- app
    |-- components
    |-- directives
    |-- mocks
    |-- pages
        |-- general   (contains elements found in all project types)
            |-- not-found
            |-- home
            |-- contact
            |-- login
            |-- signup
        |-- application  (contains the elements specific to our project)
            |-- item01
            |-- item02
            |-- ....
            |-- itemXX
     |-- pipes
     |-- services
|-- assets
|-- environments

Initialization

A quick overview before seeing the technical details

Angular offers an angular@router library which allows you to manage routing.

In versions prior to Angular 17, routing was managed as follows.

The angular@routeur library was imported into a module dedicated to routing.
This module was named app-routing.module.ts

Since version 17, routing is implicit when creating the project with Angular CLI.
​​​​​​​

Routing is thus managed via 3 basic files.

  • app.component.ts
  • app.config.ts
  • app.routes.ts

The following diagram will explain how it is managed with version 17.

Throughout this tutorial we will try to use the commands that angular-cli offers to automatically generate the necessary source code.

First we will create six components that will be used in routing.
A component will correspond to a web page.
These are six classic web pages found on any website.

  • Home
  • Contact
  • About
  • Login
  • Signup
  • NotFound

So two diagrams to summarize what we are going to do with version 17
​​​​​​​and its comparison with version 16 and earlier.

Routing with Angular 17

Angular Router

Routing with Angular 16

Angular Router

We will use angular CLI for this.

Let's run the following commands.

ng g corresponds to the ng generate command

# Creating new components (method 1)
ng generate component pages/general/contact
ng generate component pages/general/login
ng generate component pages/general/signup
ng generate component pages/general/home
ng generate component pages/general/about
ng generate component pages/general/not-found

# Creating new components (method 2)
ng g c pages/general/contact
ng g c pages/general/login
ng g c pages/general/signup
ng g c pages/general/home
ng g c pages/general/about
ng g c pages/general/not-found

The pages and pages/general directories are created by the executed command.
All files relating to each component are created automatically by Angular CLI.

For example for the Home component 4 files are created

  • home.component.css (CSS code dedicated to design)
  • home.component.html (HTML code)
  • home.component.spec.ts (component unit test code)
  • home.component.ts (logical part in typescript of our component)

​​​​​​​

You must then modify the following files

  • app-routes.ts
  • styles.css
  • app.component.html
  • app.component.css
  • app.component.ts
  • app.component.spec.ts

This will allow processing the desired routing and the components called.

src/app/app.routes.ts
import { Routes } from '@angular/router';

import { HomeComponent } from './pages/general/home/home.component';

import { LoginComponent } from './pages/general/login/login.component';
import { SignupComponent } from './pages/general/signup/signup.component';
import { NotFoundComponent } from './pages/general/not-found/not-found.component';

import { AboutComponent } from './pages/general/about/about.component';
import { ContactComponent } from './pages/general/contact/contact.component';

export const routes: Routes = [
    { path: '', component: HomeComponent, },

    { path: 'login', component: LoginComponent },
    { path: 'signup', component: SignupComponent },

    { path: 'about', component: AboutComponent },
    { path: 'contact', component: ContactComponent },

    { path: '**', component: NotFoundComponent }
];
src/styles.css
body {
  color: black;
  font-weight: 400;
}

In the AppComponent we will take care to add the <router-outlet> element to the app.component.html file.
It will tell the router where to display the routed graphic elements.

The routerLink element will create the link to the desired pages.

src/app/app.component.html
<div class="app">
  <header>
    <section>
      <h1>{{ title }}</h1>
    </section>
    <nav>
      <h2>3 Links with Routes</h2>
      <ul>
        <li><a routerLink="/">Home</a></li>
        <li><a routerLink="/login">Login</a></li>
        <li><a routerLink="/signup">Signup</a></li>
      </ul>
      <h3>2 Links with Child Routes</h3>
      <ul>
        <li><a routerLink="/about">About</a></li>
        <li><a routerLink="/contact">Contact</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <h4>Routes Result</h4>
    <router-outlet></router-outlet>
  </main>

  <footer>
    <a href="{{ footerUrl }}">{{ footerLink }}</a>
  </footer>

</div>
src/app.component.css
h1 {
  color: blue;
}

.app {
  font-family: Arial, Helvetica, sans-serif;
  max-width: 500px;
  margin: auto;
}

src/app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular-routing';
  footerUrl = 'https://www.ganatan.com';
  footerLink = 'www.ganatan.com';
}

Routing works

After all these modifications let's check that it works.
We run the launch script and test the result in the browser.

# Run the application
npm run start

# Test the app in your browser
http://localhost:4200

The program works, test the routing by clicking on the different links.

We agree it's not very pretty.
But we were quick, we used very simple HTML and CSS.

We will refine all this later using Bootstrap in a following tutorial.

Waiting for the result in pictures.

Angular et routing résultat  en image

We need to add the RouterTestingModule module to the unit tests of the App component.
This addition is done at the level of the corresponding test file app.component.spec.ts .

src/app/app.component.spec.ts
import { TestBed } from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';

import { AppComponent } from './app.component';

describe('AppComponent', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [AppComponent],
      providers: [
        {
          provide: ActivatedRoute,
          useValue: {}
        }
      ]
    }).compileComponents();
  });

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app).toBeTruthy();
  });

  it(`should have the 'angular-routing' title`, () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app.title).toEqual('angular-routing');
  });

});

Child Routes


To manage more complex routes, for example routing from the contact component, we need to address the management of Child routes.

This issue is discussed in the documentation
https://angular.io/guide/router#child-route-configuration

We are going to add three components that will be accessible from the Contact component

  • mailing
  • mapping
  • website

# Addition of the three components
ng generate component modules/general/contact/mailing --module=app
ng generate component modules/general/contact/mapping --module=app
ng generate component modules/general/contact/website --module=app

4 files are automatically created for each component for example for mailing

  • mailing.component.css
  • mailing.component.html
  • mailing.component.spec.ts
  • mailing.component.ts

We still have to modify the routing

  • contact.component.html
  • contact.component.spec.ts
  • app-routing.module.ts


  •  
contact.component.html
<div>
  <p>contact works!</p>
  <ul>
    <li><a routerLink="/contact/mailing">Mailing</a></li>
    <li><a routerLink="/contact/mapping">Mapping</a></li>
    <li><a routerLink="/contact/website">Website</a></li>
  </ul>
  <h4>Child Routes Result</h4>
  <router-outlet></router-outlet>
</div>
app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { HomeComponent } from './modules/general/home/home.component';
import { NotFoundComponent } from './modules/general/not-found/not-found.component';

import { AboutComponent } from './modules/general/about/about.component';
import { LoginComponent } from './modules/general/login/login.component';
import { SignupComponent } from './modules/general/signup/signup.component';

import { ContactComponent } from './modules/general/contact/contact.component';
import { MailingComponent } from './modules/general/contact/mailing/mailing.component';
import { MappingComponent } from './modules/general/contact/mapping/mapping.component';
import { WebsiteComponent } from './modules/general/contact/website/website.component';

const routes: Routes = [
  { path: '', component: HomeComponent, },

  { path: 'about', component: AboutComponent },
  { path: 'login', component: LoginComponent },
  { path: 'signup', component: SignupComponent },

  {
    path: 'contact', component: ContactComponent,
    children: [
      { path: '', component: MailingComponent },
      { path: 'mailing', component: MailingComponent },
      { path: 'mapping', component: MappingComponent },
      { path: 'website', component: WebsiteComponent },
    ],
  },

  { path: '**', component: NotFoundComponent }

];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  declarations: []
})
export class AppRoutingModule { }
contact.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';

import { ContactComponent } from './contact.component';

describe('ContactComponent', () => {
  let component: ContactComponent;
  let fixture: ComponentFixture<ContactComponent>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],      
      declarations: [ContactComponent]
    });
    fixture = TestBed.createComponent(ContactComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

Tests

All that remains is to test the following scripts.

# Développement
npm run start
http://localhost:4200/

# Test de la page not-found
http://localhost:4200/lien-inconnu

# Tests
npm run test

# Production
npm run build

Code source

The source code used at the beginning of the tutorial is available on github
https://github.com/ganatan/angular-react-starter

The source code obtained at the end of this tutorial is available on github
https://github.com/ganatan/angular-react-routing

The following steps will get you a prototype application.

​​​​​​​This last step provides an example of an application


The source code of this final application is available on GitHub
https://github.com/ganatan/angular-app