Tutorials Logic, IN info@tutorialslogic.com

Angular Routing Navigation Router

Router Model

The Angular Router maps browser locations to component trees. Define route records, outlets, links, parameters, and programmatic navigation so URLs remain bookmarkable and direct refresh works after deployment.

Angular Router maps browser URLs to a tree of components. A navigation recognizes route segments, evaluates redirects and guards, resolves lazy dependencies and data, activates matched components, and updates browser history without a full document reload.

A route is configuration, not a menu item. RouterLink initiates navigation, RouterOutlet marks where an activated component renders, ActivatedRoute exposes state for the current route, and Router provides imperative navigation and events.

Route Configuration

Define Routes in app.routes.ts and register them with provideRouter(routes) in ApplicationConfig. The document base href controls how relative application URLs resolve; most root-hosted applications use <base href="/">.

Put specific routes before a wildcard because Angular uses first-match wins. A redirect with an empty path normally needs pathMatch: "full" so it does not prefix-match every URL.

Child routes render in an outlet owned by their parent component. Lazy load a route with loadComponent or loadChildren when its code is not needed for the initial screen.

  • Use :id for a path parameter that identifies a resource; use query parameters for optional view state such as page, sort, or filter.
  • Use data for static route metadata and resolve only when navigation truly must wait for data.
  • Finish with a wildcard route using path "**" for a client-side not-found page.

Route Configuration Example

Route Configuration Example
<base href="/">

Standalone Routing

Standalone Routing
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { DashboardComponent } from './dashboard/dashboard.component';

export const routes: Routes = [
  { path: '',        redirectTo: 'home', pathMatch: 'full' },
  { path: 'home',      component: HomeComponent },
  { path: 'about',     component: AboutComponent },
  { path: 'dashboard', component: DashboardComponent },
  { path: '**',        redirectTo: 'home' }
];

Route Configuration Usage

Route Configuration Usage
import { ApplicationConfig } from '@angular/core';
import { provideRouter, withComponentInputBinding } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes, withComponentInputBinding())
  ]
};

RouterLink & RouterOutlet

RouterLink & RouterOutlet
<!-- Routed components will be display here -->
											<router-outlet></router-outlet>

Routing and Navigation Steps

Routing and Navigation Steps
import { Component } from '@angular/core';
import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterLink, RouterLinkActive, RouterOutlet],
  template: `
    <h1>Angular Router</h1>
    <nav>
      <a routerLink="/home"      routerLinkActive="active">Home</a>
      <a routerLink="/about"     routerLinkActive="active">About</a>
      <a routerLink="/dashboard" routerLinkActive="active">Dashboard</a>
    </nav>
    <router-outlet />
  `
})
export class AppComponent { }

Programmatic Navigation

Use RouterLink in templates because it preserves normal link semantics and accessibility. Use Router.navigate for navigation triggered after TypeScript work such as a successful save, and Router.navigateByUrl when you already have a complete URL string.

Commands passed to navigate can be absolute or relative to an ActivatedRoute. NavigationExtras controls query parameters, fragments, history replacement, and browser state.

Programmatic Navigation Example

Programmatic Navigation Example
import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'app-home',
  standalone: true,
  template: `
    <h2>Home</h2>
    <button (click)="goToDashboard()">Go to Dashboard</button>
  `
})
export class HomeComponent {
  private router = inject(Router);

  goToDashboard() {
    this.router.navigate(['/dashboard']);
  }
}

Route State

ActivatedRoute exposes paramMap, queryParamMap, data, fragment, URL segments, parent, and children. Snapshot is suitable when the component cannot stay mounted while the value changes. Subscribe or convert the observable to a signal when the router may reuse the same component for a new parameter.

withComponentInputBinding can bind route parameters, query parameters, static data, and resolver data directly to matching component inputs. This keeps route-aware components easy to test because their data contract remains explicit.

  • Read a one-time value with route.snapshot.paramMap.get("id").
  • React to reused-route changes with route.paramMap or a component input binding.
  • Validate and parse URL strings before treating them as domain values.

Reactive Route Parameter

Reactive Route Parameter
import { Component, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { map } from 'rxjs';
import { toSignal } from '@angular/core/rxjs-interop';

@Component({
  selector: 'app-product-page',
  template: `<p>Product ID: {{ productId() }}</p>`
})
export class ProductPageComponent {
  private route = inject(ActivatedRoute);
  productId = toSignal(
    this.route.paramMap.pipe(map(params => params.get('id') ?? '')),
    { initialValue: '' }
  );
}

The signal updates if navigation changes /products/1 to /products/2 while Angular reuses the same component instance.

Nested Routes

Nested routes model a nested UI. The parent component stays active while a child component renders in its router-outlet. This is useful for settings, account, and admin shells with persistent navigation.

Route guards can improve navigation flow, but all authorization must be enforced by the backend. A user can modify client code and call an API directly.

Settings Route Tree

Settings Route Tree
export const routes: Routes = [
  {
    path: 'settings',
    component: SettingsShellComponent,
    children: [
      { path: '', redirectTo: 'profile', pathMatch: 'full' },
      { path: 'profile', component: ProfileSettingsComponent },
      { path: 'security', loadComponent: () =>
          import('./security-settings.component')
            .then(module => module.SecuritySettingsComponent) }
    ]
  },
  { path: '**', component: NotFoundComponent }
];

SettingsShellComponent must import RouterOutlet. The security child is lazy while the parent shell and other child route stay available.

Navigation Events Titles and Scrolling

Router.events exposes the navigation lifecycle for diagnostics, analytics, and global progress. Filter for the event type required by the feature and bind imperative subscriptions with takeUntilDestroyed. Do not infer completion from a click because guards, redirects, resolvers, or lazy loading may still cancel or replace the navigation.

Set route title for document titles and extend TitleStrategy when the application needs a shared suffix or hierarchical rule. Configure scroll restoration and anchor scrolling through router features, then test browser back and forward behavior with long pages.

  • NavigationEnd represents a successfully completed navigation after redirects.
  • NavigationCancel, NavigationError, and NavigationSkipped are different outcomes and should not be counted as successful page views.
  • Use replaceUrl for redirects that should not leave a useless history entry and state for non-bookmarkable navigation metadata.

Configure Titles and Scroll Restoration

Configure Titles and Scroll Restoration
export const routes: Routes = [
  { path: '', title: 'Catalog', component: CatalogPage },
  { path: 'products/:id', title: 'Product', component: ProductPage }
];

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(
      routes,
      withInMemoryScrolling({
        scrollPositionRestoration: 'enabled',
        anchorScrolling: 'enabled'
      })
    )
  ]
};

Testing Router Behavior

Test route recognition, redirects, bound inputs, guards, and rendered destinations through RouterTestingHarness with a focused route configuration. This proves the public navigation contract without starting a development server.

Use a browser or end-to-end test for real history traversal, scroll restoration, server fallback, base href, and direct URL refresh because those behaviors depend on the browser and deployment host.

  • Provide only the routes and fakes required by the behavior under test.
  • Navigate by URL and assert the activated component or rendered outlet.
  • Include direct deep links and a not-found URL in deployed smoke tests.

Test a Parameterized Route

Test a Parameterized Route
TestBed.configureTestingModule({
  providers: [
    provideRouter([
      { path: 'products/:id', component: ProductPageComponent }
    ])
  ]
});

const harness = await RouterTestingHarness.create();
const page = await harness.navigateByUrl(
  '/products/42',
  ProductPageComponent
);

expect(page.productId()).toBe('42');
Confirm the page outcome

Router Review

5 checks
  • I can configure redirects, parameterized routes, lazy routes, child routes, and a wildcard not-found route in the correct order.
  • I can choose RouterLink or Router.navigate and preserve accessible navigation behavior.
  • I can read snapshot state once or react to parameter changes when a component is reused.
  • I know route guards do not replace server-side authorization.
  • I can configure titles and scrolling, interpret navigation outcomes, and test routes with RouterTestingHarness.

Routing Failure Boundary

  • Navigation loops

    Avoid guards that redirect to a route protected by the same failing guard. Return one UrlTree to the intended recovery route and test direct URLs as well as in-app links.

Router Review Questions

router.navigate() keeps the single-page application running, applies guards and resolvers, updates router state, and avoids downloading the app again. Assigning window.location asks the browser for a new document and restarts Angular.

The default matching strategy is prefix, and every URL begins with the empty string. An empty redirect can therefore match more routes than intended and repeatedly redirect navigation. pathMatch: 'full' tells Angular to apply the redirect only when the entire remaining URL is empty.

routerLinkActive uses prefix matching by default, so a link targeting / can appear active for every URL that begins at the root. Add routerLinkActiveOptions with exact: true to the home link when it should match only the exact home route.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.