Routing in Angular 17

You can navigate to a different view in Angular either from a link in template or via JavaScript. Here is an example of going to another page using routerLink directive inside a template:

// home.component.ts
import { RouterLink } from '@angular/router';
@Component({
  selector: 'app-home',
  standalone: true,
  imports: [RouterLink],
  template: `
    <a routerLink="/products">Products</a>
  `,
})
export class HomeComponent {}

For this to work products path should be set in app.routes.ts:

//app.routes.ts
import { Routes } from '@angular/router';
import { ProductsComponent } from './products.component';
export const routes: Routes = [
  {
    path: 'products',
    title: 'Products',
    component: ProductsComponent
  }
];

The other approach would be to use navigate method of Router service to go to a new page. Below is an example of clicking a button to do the same thing as above. Note that we need to inject the Router service into our component:

// home.component.ts
import { RouterLink } from '@angular/router';
@Component({
  selector: 'app-home',
  standalone: true,
  imports: [RouterLink],
  template: `
    <button (click)="goto('/products')">Products</button>
  `,
})
export class HomeComponent {
  constructor(private router: Router) {}
  goto(url: string) {
    this.router.navigate([url]);
}

Now let's say we want products page show a specific product by sending the id of a product. We need to change the link in template so that it includes a router parameter. In Angular router parameter and query parameter are different things. A query parameter is an optional parameter which is not part of the route and is added to a url with a such syntax: /products?sort=type. A route parameter however is not optional, that is it is part of the route itself and follows a syntax like this: /products/1. This url represents a route that is defined as /products/:id, so if you use route parameters you need to make sure your routes in app.routes.ts are set properly to support them, but if you use query parameters you don't need to make any changes to your routes since these parameters are not part of the route.

Let's update our link by adding a route parameter to create a link to a specific product:

<a [routerLink]="['/products', '1']">Products</a>

Now the link will direct user to url /products/1, so we need to add a route for it to app.routes.ts:

  {
    path: 'products',
    title: 'Products',
    component: ProductsComponent
  },
  {
    path: 'products/:id',
    title: 'Products',
    component: ProductsComponent
  }

We could send this id as a query parameter without defining a new route, even though it's not a good practice. In that case our link would have looked like this:

<a routerLink="/products" [queryParams]="{id: '1'}">Products</a>

The above link will direct user to url /products?id=1.

Regardless of which method you choose, you can access the id parameter in ProductsComponent using @Input() decorator and without need to import ActivatedRoute service. This is possible in Angular 17 by importing withComponentInputBinding provider in app.config.ts:

// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter, withComponentInputBinding } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes, withComponentInputBinding())
  ]
};

On products page we show a list of all products when no id is available or name of the specific product when an id is sent:

// products.component.ts
import { Component, Input } from '@angular/core';
import { NgFor } from '@angular/common';
@Component({
  selector: 'app-products',
  standalone: true,
  imports: [NgFor],
  template: `
    <h1>Products</h1>
    @if (id) {
      <p>{{getProduct(id)}}</p>
    } @else {
      <ul *ngFor="let product of products">
        <li>{{product.name}}</li>
      </ul>
    }
  `
})
export class ProductsComponent {
    @Input() id: string | undefined;
    products = [
      { id: 1, name: 'Apple' },
      { id: 2, name: 'Banana' },
      { id: 3, name: 'Pear' }
    ];
    getProduct(id: string) {
      const product = this.products.find(item => item.id === Number(id));
      return product ? product.name : `No product found for id: ${id}`;
    }
}

We can also use navigate method of Router service to go to a new page with a parameter:

// home.component.ts
import { RouterLink } from '@angular/router';
@Component({
  selector: 'app-home',
  standalone: true,
  imports: [RouterLink],
  template: `
    <button (click)="goto('/products', '3')">Products</button>
  `,
})
export class HomeComponent {
  constructor(private router: Router) {}
  goto(url: string, id: string) {
    // takes us to /products/3
    this.router.navigate([url, id]);

    // takes us to /products?id=3
    //this.router.navigate(
      //[url],
      //{ queryParams: { id: id } }
    //);
  }
}

Further reading: