How to Pass Data to Angular Routed Components: A Complete TypeScript Guide
\n\nEvery developer who starts working with Angular eventually faces the question: "How do I pass data from one component to another through the router?". On Stack Overflow, this question has gathered thousands of views — and for good reason. Unlike regular parent-child components, where using @Input() and @Output() is sufficient, routing in Angular adds its own complexities.
In this article, we will cover 5 proven ways to pass data in Angular routed components. You will learn when to use which method and get ready-to-use examples in TypeScript. Let's go!
\n\nWhy Can't You Just Pass Data via @Input?
\n\nMany beginners try to do this:
\n\n// ❌ This doesn't work\n<router-outlet [someData]="data"></router-outlet>\n\nThe Angular Router creates components dynamically. router-outlet is a directive, not a template element. Therefore, passing data directly through attributes is impossible. But there are workarounds — and they are even more convenient!
Method 1: Using Router State (Simplest)
\n\nThe most intuitive way is to pass data through the state object during navigation. This method has been available since Angular 7+ and works out of the box.
How It Works
\n\nYou pass an object with data when calling router.navigate() or via routerLink.
// Component A — sender\nimport { Component } from '@angular/core';\nimport { Router } from '@angular/router';\n\n@Component({\n selector: 'app-user-list',\n template: `\n <button (click)="goToDetails()">Open User</button>\n `\n})\nexport class UserListComponent {\n constructor(private router: Router) {}\n\n goToDetails() {\n this.router.navigate(['/user', 42], {\n state: { name: 'Ivan Petrov', role: 'admin' }\n });\n }\n}\n\n// Component B — receiver\nimport { Component, OnInit } from '@angular/core';\nimport { Router } from '@angular/router';\n\n@Component({\n selector: 'app-user-details',\n template: `\n <div *ngIf="userData">\n <h2>{{ userData.name }}</h2>\n <p>Role: {{ userData.role }}</p>\n </div>\n `\n})\nexport class UserDetailsComponent implements OnInit {\n userData: any;\n\n constructor(private router: Router) {\n // Get data from navigation history\n this.userData = this.router.getCurrentNavigation()?.extras?.state;\n }\n\n ngOnInit() {\n // Alternative method — via history.state\n if (!this.userData) {\n this.userData = history.state;\n }\n }\n}\n\nPros and Cons
\n- \n
- ✅ Simple to implement \n
- ✅ Data is not visible in the URL \n
- ✅ Works with any data types (objects, arrays) \n
- ❌ Data is lost on page refresh \n
- ❌ Does not work when navigating directly via URL \n
When to use: for passing temporary data that is not critical on reload (e.g., flash messages, filters).
\n\nMethod 2: Route Resolver (For Preloading Data)
\n\nIf you need to load data before the component is displayed, use an Angular Resolver. This is a service that resolves data before the route is activated.
\n\nCreating a Resolver
\n\n// user.resolver.ts\nimport { Injectable } from '@angular/core';\nimport { Resolve, ActivatedRouteSnapshot } from '@angular/router';\nimport { Observable, of } from 'rxjs';\n\n@Injectable({ providedIn: 'root' })\nexport class UserResolver implements Resolve<any> {\n resolve(route: ActivatedRouteSnapshot): Observable<any> {\n const userId = route.paramMap.get('id');\n // Im