Introduction
In this blog post, I want to describe a new feature called redirect functions with routes. When defining routes in Angular, it is possible to catch and redirect a route to a different path using redirectTo
. One example is to catch all unknown routes and redirect them to a 404 page. Another example is redirecting a default route to a home page. In Angular 18, redirectTo
is enhanced to accept a function. Then, a route can perform logic in the function and route to different paths according to some criteria.
I will demonstrate how I made typos in the routes and used the redirect routes to functions technique to redirect them to the routes with the correct spelling.
Update Application Config to add routing
// app.config.ts
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideRouter(routes, withComponentInputBinding()),
provideExperimentalZonelessChangeDetection()
]
};
provideRouter(routes, withComponentInputBinding())
add routes to the demo to navigate to Pokemon List and Pokemon Details respectively.
// main.ts
import { appConfig } from './app.config';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
template: `
<h2>redirectTo Demo</h2>
<router-outlet />
`,
})
export class App {}
bootstrapApplication(App, appConfig);
Bootstrap the component and the application configuration to start the Angular application.
Create routes for navigation to Pokemon list and Pokemon Details
I wanted to add two new routes to load the components but I made typos in the configuration. I typed /pokermon-list
instead of /pokemon-list
. Similarly, I typed /pokermon-list/:name instead of the correct spelling /pokemon-list/:name.
// app.route.ts
export const routes: Routes = [
{
path: 'pokermon-list',
loadComponent: () => import('./pokemons/pokemon-list/pokemon-list.component'),
title: 'Pokermon List',
},
{
path: 'pokemon-list/:name',
loadComponent: () => import('./pokemons/pokemon/pokemon.component'),
title: 'Pokermon',
},
{
path: '',
pathMatch: 'full',
redirectTo: 'pokermon-list'
},
{
path: '**',
redirectTo: 'pokermon-list'
}
];
The careless mistakes went unnoticed, and I copied and pasted the erroneous routes to the routeLink
in the inline templates.
Add routing in the template
// pokemon-list.component.ts
div class="container">
@for(p of pokemons(); track p.name) {
<div class="card">
<p>Name: <a [routerLink]="['/pokermon-list', p.name]">{{ p.name }}</a></p>
</div>
}
</div>
In the Pokemon List component, the first element of the routerLink
is /pokermon-list
.
// pokemon.component.ts
<div>
<a [routerLink]="'/pokermon-list'">Back</a>
</div>
In the Pokemon component, the value of the routerLink
is /pokermon-list
to go back to the previous page.
Someone spotted the typos in the URL and informed me. I easily fixed the typos in the routerLink and the routes array.
Fix the errors in routes
// app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: 'pokemon-list',
loadComponent: () => import('./pokemons/pokemon-list/pokemon-list.component'),
title: 'Pokermon List',
},
{
path: 'pokemon-list/:name',
loadComponent: () => import('./pokemons/pokemon/pokemon.component'),
title: 'Pokermon',
},
{
path: '',
pathMatch: 'full',
redirectTo: 'pokemon-list'
},
{
path: '**',
redirectTo: 'pokemon-list'
}
];
All occurrences of pokermon-list
were replaced with pokemon-list
in the routes array.
// pokemon-list.component.ts
div class="container">
@for(p of pokemons(); track p.name) {
<div class="card">
<p>Name: <a [routerLink]="['/pokemon-list', p.name]">{{ p.name }}</a></p>
</div>
}
</div>
// pokemon.component.ts
<div>
<a [routerLink]="'/pokemon-list'">Back</a>
</div>
Similarly, the templates replaced /pokermon-list
with /pokemon-list
in the routerLink
inputs.
This should work, but I wanted to improve my new solution. If someone bookmarked /pokermon-list
or /pokermon-list/pikachu
before, these URLs do not work now. Instead, the URLs must redirect to /pokemon-list
and /pokemon-list/pikachu
.
I will show you how it can be done by using the new redirectTo function in Angular 18.
Redirect routes with function
// app.routes.ts
export const routes: Routes = [
{
path: 'pokemon-list',
loadComponent: () => import('./pokemons/pokemon-list/pokemon-list.component'),
title: 'Pokermon List',
},
{
path: 'pokemon-list/:name',
loadComponent: () => import('./pokemons/pokemon/pokemon.component'),
title: 'Pokermon',
},
{
path: 'pokermon-list',
redirectTo: 'pokemon-list',
},
{
path: 'pokermon-list/:name',
redirectTo: ({ params }) => {
const name = params?.['name'] || '';
return name ? `/pokemon-list/${name}` : 'pokemon-list';
}
},
{
path: '',
pathMatch: 'full',
redirectTo: 'pokemon-list'
},
{
path: '**',
redirectTo: 'pokemon-list'
}
];
redirectTo
accepts a string or a function; therefore, I redirected /pokermon-list
to /pokemon-list
. This is the same behavior before Angular 18.
The /pokermon-list/:name
route was tricky because I wanted to redirect to /pokemon-list/:name
when the name route parameter was present and to /pokemon-list when the name route parameter was missing. I satisfied the requirements by redirecting the route with a function.
{
path: 'pokermon-list/:name',
redirectTo: ({ params }) => {
const name = params?.['name'] || '';
return name ? `/pokemon-list/${name}` : 'pokemon-list';
}
},
I de-structured params
from ActivatedRouteSnapshot
and found the value of the name property in the record. When the string was not empty, users were directed to see the Pokemon details, and when it was empty, they were redirected to the Pokemon list.
The full listing of the routes array
// app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: 'pokemon-list',
loadComponent: () => import('./pokemons/pokemon-list/pokemon-list.component'),
title: 'Pokermon List',
},
{
path: 'pokemon-list/:name',
loadComponent: () => import('./pokemons/pokemon/pokemon.component'),
title: 'Pokermon',
},
{
path: 'pokermon-list',
redirectTo: 'pokemon-list',
},
{
path: 'pokermon-list/:name',
redirectTo: ({ params }) => {
const name = params?.['name'] || '';
return name ? `/pokemon-list/${name}` : 'pokemon-list';
}
},
{
path: '',
pathMatch: 'full',
redirectTo: 'pokemon-list'
},
{
path: '**',
redirectTo: 'pokemon-list'
}
];
This is the full listing of the routes array where navigation and redirection work as expected.
The following Stackblitz repo displays the final results:
This is the end of the blog post that describes redirecting routes with redirect functions in Angular. I hope you like the content and continue to follow my learning experience in Angular, NestJS, GenerativeAI, and other technologies.
Resources:
- Stackblitz Demo: https://stackblitz.com/edit/stackblitz-starters-h1eyk9?file=src%2Fapp.routes.ts
- Github Repo: https://github.com/railsstudent/ng-redirectTo-demo
- Github Page: https://railsstudent.github.io/ng-redirectTo-demo