|
| 1 | +--- |
| 2 | +title: injectLeafActivatedRoute |
| 3 | +description: ngxtension/inject-leaf-activated-route |
| 4 | +entryPoint: ngxtension/inject-leaf-activated-route |
| 5 | +badge: stable |
| 6 | +contributors: ['max-scopp'] |
| 7 | +--- |
| 8 | + |
| 9 | +:::note[Router outlet is required] |
| 10 | +`injectLeafActivatedRoute` works on all components that are inside routing context. Make sure the component you are using `injectLeafActivatedRoute` in is part of your routes. |
| 11 | +::: |
| 12 | + |
| 13 | +`injectLeafActivatedRoute` is a helper function that returns a signal containing the deepest (leaf) activated route in the router state tree. |
| 14 | + |
| 15 | +The leaf route is the deepest child route that has no children of its own. This is useful when you need to access route information from the currently active, deepest route regardless of your component's position in the route hierarchy. |
| 16 | + |
| 17 | +Having the leaf route as a signal helps in a modern Angular signals-based architecture and automatically updates whenever navigation ends. |
| 18 | + |
| 19 | +```ts |
| 20 | +import { injectLeafActivatedRoute } from 'ngxtension/inject-leaf-activated-route'; |
| 21 | +``` |
| 22 | + |
| 23 | +## Usage |
| 24 | + |
| 25 | +### Get the leaf activated route |
| 26 | + |
| 27 | +`injectLeafActivatedRoute` when called, returns a signal with the current leaf activated route. |
| 28 | + |
| 29 | +```ts |
| 30 | +@Component({ |
| 31 | + standalone: true, |
| 32 | + template: ` |
| 33 | + <div>Current route: {{ leafRoute().snapshot.url }}</div> |
| 34 | + <div>Route params: {{ leafRoute().snapshot.params | json }}</div> |
| 35 | + `, |
| 36 | +}) |
| 37 | +class MyComponent { |
| 38 | + leafRoute = injectLeafActivatedRoute(); |
| 39 | +} |
| 40 | +``` |
| 41 | + |
| 42 | +### Access route parameters from leaf route |
| 43 | + |
| 44 | +The most common use case is to access route parameters from the deepest active route, regardless of where your component is in the component tree. |
| 45 | + |
| 46 | +```ts |
| 47 | +@Component({ |
| 48 | + template: ` |
| 49 | + @if (user(); as user) { |
| 50 | + <div>{{ user.name }}</div> |
| 51 | + } @else { |
| 52 | + <div>Loading...</div> |
| 53 | + } |
| 54 | + `, |
| 55 | +}) |
| 56 | +class ParentComponent { |
| 57 | + leafRoute = injectLeafActivatedRoute(); |
| 58 | + |
| 59 | + // Access the 'id' param from the leaf route |
| 60 | + userId = computed(() => this.leafRoute().snapshot.params['id']); |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +### Access multiple route parameters |
| 65 | + |
| 66 | +```ts |
| 67 | +@Component({ |
| 68 | + template: ` |
| 69 | + <div>Organization: {{ orgId() }}</div> |
| 70 | + <div>User: {{ userId() }}</div> |
| 71 | + `, |
| 72 | +}) |
| 73 | +class DashboardComponent { |
| 74 | + leafRoute = injectLeafActivatedRoute(); |
| 75 | + |
| 76 | + orgId = computed(() => this.leafRoute().snapshot.params['orgId']); |
| 77 | + userId = computed(() => this.leafRoute().snapshot.params['userId']); |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +### Access query parameters |
| 82 | + |
| 83 | +You can also access query parameters from the leaf route: |
| 84 | + |
| 85 | +```ts |
| 86 | +@Component({ |
| 87 | + template: ` |
| 88 | + <div>Search query: {{ searchQuery() }}</div> |
| 89 | + `, |
| 90 | +}) |
| 91 | +class SearchComponent { |
| 92 | + leafRoute = injectLeafActivatedRoute(); |
| 93 | + |
| 94 | + searchQuery = computed( |
| 95 | + () => this.leafRoute().snapshot.queryParams['query'] ?? '', |
| 96 | + ); |
| 97 | +} |
| 98 | +``` |
| 99 | + |
| 100 | +### Access route data |
| 101 | + |
| 102 | +Access static or resolved data from the leaf route: |
| 103 | + |
| 104 | +```ts |
| 105 | +@Component({ |
| 106 | + template: ` |
| 107 | + <div>Requires auth: {{ requiresAuth() }}</div> |
| 108 | + `, |
| 109 | +}) |
| 110 | +class AdminComponent { |
| 111 | + leafRoute = injectLeafActivatedRoute(); |
| 112 | + |
| 113 | + requiresAuth = computed( |
| 114 | + () => this.leafRoute().snapshot.data['requiresAuth'] ?? false, |
| 115 | + ); |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +## Why use this over `inject(ActivatedRoute)`? |
| 120 | + |
| 121 | +When you inject `ActivatedRoute` directly, you get the route associated with the current component. This might not be the deepest route if you have nested routes with child components. |
| 122 | + |
| 123 | +`injectLeafActivatedRoute` always gives you the deepest active route, which is often what you need when you want to access parameters from the currently displayed page, regardless of your component's position in the route hierarchy. |
| 124 | + |
| 125 | +### Example scenario |
| 126 | + |
| 127 | +Consider this route structure: |
| 128 | + |
| 129 | +``` |
| 130 | +/dashboard/:orgId/users/:userId |
| 131 | +``` |
| 132 | + |
| 133 | +With this component hierarchy: |
| 134 | + |
| 135 | +``` |
| 136 | +DashboardComponent (at /dashboard/:orgId) |
| 137 | + └─ UsersComponent (at users/:userId) |
| 138 | +``` |
| 139 | + |
| 140 | +In `DashboardComponent`, if you use `inject(ActivatedRoute)`, you only get access to `orgId`. But with `injectLeafActivatedRoute()`, you can access both `orgId` and `userId` because it gives you the deepest route. |
| 141 | + |
| 142 | +## Reactive updates |
| 143 | + |
| 144 | +The signal automatically updates whenever navigation ends, ensuring it always reflects the current leaf route: |
| 145 | + |
| 146 | +```ts |
| 147 | +@Component({ |
| 148 | + template: ` |
| 149 | + <div>Current user ID: {{ userId() }}</div> |
| 150 | + <button (click)="navigateToUser('123')">User 123</button> |
| 151 | + <button (click)="navigateToUser('456')">User 456</button> |
| 152 | + `, |
| 153 | +}) |
| 154 | +class UserListComponent { |
| 155 | + router = inject(Router); |
| 156 | + leafRoute = injectLeafActivatedRoute(); |
| 157 | + |
| 158 | + userId = computed(() => this.leafRoute().snapshot.params['id']); |
| 159 | + |
| 160 | + navigateToUser(id: string) { |
| 161 | + this.router.navigate(['/users', id]); |
| 162 | + // The userId signal will automatically update after navigation |
| 163 | + } |
| 164 | +} |
| 165 | +``` |
| 166 | + |
| 167 | +## Use with other inject utilities |
| 168 | + |
| 169 | +`injectLeafActivatedRoute` works great with other ngxtension utilities like `injectParams` and `injectQueryParams`, but it's particularly useful when you need access to the full route object or when building reusable components that need to be aware of the current route state. |
| 170 | + |
| 171 | +```ts |
| 172 | +import { injectParams } from 'ngxtension/inject-params'; |
| 173 | + |
| 174 | +@Component({}) |
| 175 | +class MyComponent { |
| 176 | + // Using injectParams with global option |
| 177 | + // internally uses injectLeafActivatedRoute |
| 178 | + userId = injectParams('id', { global: true }); |
| 179 | + |
| 180 | + // Or use injectLeafActivatedRoute directly for more control |
| 181 | + leafRoute = injectLeafActivatedRoute(); |
| 182 | + allParams = computed(() => this.leafRoute().snapshot.params); |
| 183 | +} |
| 184 | +``` |
0 commit comments