typescript
42 lines · 8 steps
Route-scoped providers and lazy loading in Angular
A feature route tree that scopes its own services, lazy-loads components, and resolves data with functional route guards.
Explained by
highlit
1import { Routes } from '@angular/router';
2import { inject } from '@angular/core';
3import { HttpClient } from '@angular/common/http';
4import { REPORT_API_URL } from './reports/report.tokens';
5import { ReportStore } from './reports/report.store';
6import { canDeactivateReport } from './reports/report.guard';
7
8export const reportRoutes: Routes = [
9 {
10 path: 'reports',
11 providers: [
12 ReportStore,
13 { provide: REPORT_API_URL, useValue: '/api/v2/reports' },
14 ],
15 loadComponent: () =>
16 import('./reports/report-shell.component').then((m) => m.ReportShellComponent),
17 children: [
18 {
19 path: '',
20 pathMatch: 'full',
21 loadComponent: () =>
22 import('./reports/report-list.component').then((m) => m.ReportListComponent),
23 resolve: {
24 summaries: () => inject(ReportStore).loadSummaries(),
25 },
26 },
27 {
28 path: ':id',
29 canDeactivate: [canDeactivateReport],
30 loadComponent: () =>
31 import('./reports/report-detail.component').then((m) => m.ReportDetailComponent),
32 resolve: {
33 report: (route) => {
34 const http = inject(HttpClient);
35 const url = inject(REPORT_API_URL);
36 return http.get(`${url}/${route.paramMap.get('id')}`);
37 },
38 },
39 },
40 ],
41 },
42];
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Attaching providers to a route scopes services and tokens to that route subtree instead of the whole app.
- 2loadComponent defers a component's code until the route activates, shrinking the initial bundle.
- 3Functional resolvers and guards use inject() to pull dependencies without a constructor or class.
Related explainers
typescript
import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; import localeDe from '@angular/common/locales/de';
Locale-aware bootstrapping in Angular
i18n
localization
dependency-injection
Intermediate
8 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Cache } from 'cache-manager'; import { InjectRepository } from '@nestjs/typeorm';
A cache-aside country lookup in NestJS
cache-aside
dependency-injection
batch-lookup
Intermediate
8 steps
java
package com.acme.billing.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties;
Feature-flagged beans with Spring @ConditionalOnProperty
feature-flags
conditional-beans
strategy-pattern
Intermediate
5 steps
typescript
import { Injectable, effect, signal, computed } from '@angular/core'; interface Preferences { theme: 'light' | 'dark';
A signal-based preferences store in Angular
signals
state-management
persistence
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/route-scoped-providers-and-lazy-loading-in-angular-explained-typescript-e08f/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.