Pre-Fetch Data Before the Route Renders
Data Resolvers
A resolver fetches data while the navigation is in flight, so the component has it ready as soon as it mounts.
What you'll learn
- Write a functional ResolveFn
- Attach it via the resolve key on a route
- Read resolved data from ActivatedRoute
A resolver is a function that returns data — sync, Promise, or Observable. The route will not activate until the resolver completes, so the component mounts with data already populated.
Define a resolver
import { inject } from '@angular/core';
import { ResolveFn } from '@angular/router';
import { UsersService } from './users.service';
export interface User { id: string; name: string }
export const userResolver: ResolveFn<User> = (route) => {
const id = route.paramMap.get('id')!;
return inject(UsersService).getOne(id);
}; Attach to the route
export const routes: Routes = [
{
path: 'users/:id',
component: UserComponent,
resolve: { user: userResolver },
},
]; Read in the component
import { Component, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-user',
standalone: true,
template: `<h1>{{ user.name }}</h1>`,
})
export class UserComponent {
private route = inject(ActivatedRoute);
user = this.route.snapshot.data['user'] as User;
} When to use resolvers
Resolvers feel tidy but they delay the entire navigation — the user stares at the old page until the data lands. For most UIs, a loading skeleton inside the new component is better UX. Reach for resolvers when you genuinely need the data to render anything meaningful and want to avoid layout shift.
Lazy-Loaded Routes →