# Dependency Injection

Course: [Angular](https://www.devtutorials.ai/learn/angular) · Section: Angular Services
Source: https://www.devtutorials.ai/learn/angular/services/dependency-injection

> How Angular dependency injection works: tokens, providers, providedIn, the injector hierarchy, root and component-level providers, injection tokens, scope and lifetime.

## Introduction to Dependency Injection

A **dependency** is an object that a class needs to do its work. For example, `OrderService` needs `LoggerService` to write log messages.

**Dependency Injection (DI)** is how a class gets these objects. The class does not create them itself. It asks Angular for them, and Angular gives them to the class.

You already used DI in the previous lesson. When you wrote `inject(CartService)`, you asked Angular for the cart service.

### Real-World Example

An order page asks Angular for a `NotificationService` to message the customer. In India, the app gives it an `SmsNotificationService`. In Europe, it gives an `EmailNotificationService`.

The order page code stays the same in both countries.

If a class writes `new LoggerService()`, it can only use that exact class. With DI, the class only says which service it needs. You can then give it a different class without changing the code of the class.

| Point | Create with `new` | Dependency injection |
|---|---|---|
| Who creates the object | The class itself | Angular |
| Share one object between classes | Hard, because each `new` creates another object | Angular shares one object for you |
| Use a fake class in tests | You must edit the class | You change one provider |
| The dependency needs other services | You must create those services too | Angular creates them for you |

## How Dependency Injection Works

DI has three parts. Learn these three words first, because the rest of the lesson uses them.

### Token

A **token** is the name you use to ask for a dependency. Usually the token is the class itself. In `inject(LoggerService)`, the token is `LoggerService`.

### Provider

A **provider** is a rule that tells Angular how to create the value for a token. For example: "For the token `LoggerService`, create a new `LoggerService` object."

### Injector

An **injector** is the part of Angular that does the work. It stores the providers, creates the objects and keeps them, so it can give the same object again later.

<figure className="ngc-fig">
<svg viewBox="0 0 640 140" role="img" aria-label="Dependency injection: a class asks, the injector looks up a provider, creates the instance once, and delivers it.">
<defs><marker id="ngc-d1" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0 0L10 5L0 10z" className="ngc-arrowhead" /></marker></defs><g className="ngc-step ngc-t1"><g className="ngc-node ngc-soft c-blue"><rect x="6" y="36" width="142" height="60" rx="9" /><text x="77.0" y="63" textAnchor="middle" style={{fontSize:"15px"}}>1. Ask</text><text className="ngc-sub" x="77.0" y="81" textAnchor="middle">inject(Logger)</text></g></g><line className="ngc-link ngc-flow c-slate" x1="150" y1="66" x2="162" y2="66" markerEnd="url(#ngc-d1)" /><g className="ngc-step ngc-t2"><g className="ngc-node ngc-soft c-orange"><rect x="164" y="36" width="142" height="60" rx="9" /><text x="235.0" y="63" textAnchor="middle" style={{fontSize:"15px"}}>2. Look up</text><text className="ngc-sub" x="235.0" y="81" textAnchor="middle">find a provider</text></g></g><line className="ngc-link ngc-flow c-slate" x1="308" y1="66" x2="320" y2="66" markerEnd="url(#ngc-d1)" /><g className="ngc-step ngc-t3"><g className="ngc-node ngc-soft c-purple"><rect x="322" y="36" width="142" height="60" rx="9" /><text x="393.0" y="63" textAnchor="middle" style={{fontSize:"15px"}}>3. Create</text><text className="ngc-sub" x="393.0" y="81" textAnchor="middle">only the first time</text></g></g><line className="ngc-link ngc-flow c-slate" x1="466" y1="66" x2="478" y2="66" markerEnd="url(#ngc-d1)" /><g className="ngc-step ngc-t4"><g className="ngc-node ngc-soft c-green"><rect x="480" y="36" width="142" height="60" rx="9" /><text x="551.0" y="63" textAnchor="middle" style={{fontSize:"15px"}}>4. Deliver</text><text className="ngc-sub" x="551.0" y="81" textAnchor="middle">same instance</text></g></g><text className="ngc-note" x="320" y="124" textAnchor="middle">The injector keeps the instance, so the next request skips step 3.</text>
</svg>
<figcaption>How Angular resolves one dependency.</figcaption>
</figure>

### The Steps

When a class calls `inject(LoggerService)`, Angular follows these steps:

1. The injector looks for a provider for the token `LoggerService`.
2. The first time, it creates a `LoggerService` object with the provider and keeps it.
3. It returns the object to the class.
4. On every later request, it returns the same object. It does not create a new one.

If the injector finds no provider, Angular throws a `NullInjectorError`.

In the next example, the component asks only for `PaymentService`. But `PaymentService` needs `LoggerService`, so Angular creates `LoggerService` first.

```angular runnable title="Angular resolves a chain of dependencies"
import { Component, Injectable, inject, signal } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class LoggerService {
  readonly lines = signal<string[]>(['LoggerService created']);
  log(message: string) {
    this.lines.update(list => [...list, message]);
  }
}

@Injectable({ providedIn: 'root' })
export class PaymentService {
  private logger = inject(LoggerService);
  constructor() {
    this.logger.log('PaymentService created');
  }
  pay(amount: number) {
    this.logger.log(`Paid $${amount}`);
  }
}

@Component({
  selector: 'app-root',
  template: `
    <button (click)="payments.pay(25)">Pay $25</button>
    @for (line of logger.lines(); track $index) {
      <p>{{ line }}</p>
    }
  `,
})
export class App {
  payments = inject(PaymentService);
  logger = inject(LoggerService);
}
```

Click **Pay $25** several times. A new "Paid" line appears each time, but no new "created" line appears. This shows that Angular reuses the same objects.

## Providers

A provider tells the injector what to return for a token. You can add providers in two places:

- In the `providers` array of a component. Then the provider works for that component and its child components.
- In `app.config.ts`. Then the provider works for the whole app.

A provider can be written in different forms. Each form creates the value in a different way.

Here is one example of each form. They use the same classes as the practice block below.

```ts
providers: [
  PriceService,                                             // 1. class name only
  { provide: PriceService, useClass: RupeePriceService },   // 2. useClass
  { provide: StoreConfig, useValue: { storeName: 'Gadget Hub' } }, // 3. useValue
  { provide: Clock, useFactory: () => new Clock(14) },      // 4. useFactory
  { provide: OldLogger, useExisting: LoggerService },       // 5. useExisting
]
```

How to read a provider object:

- **`provide`** is the token, the name that a class asks for with `inject()`.
- **`useClass`**, **`useValue`**, **`useFactory`** or **`useExisting`** tells Angular what to give for that token.

| Form | What `inject()` returns | When to use it |
|---|---|---|
| 1. Class name only | A new object of that class | Most cases |
| 2. `useClass` | A new object of a **different** class: `RupeePriceService` for `PriceService` | Change the class, for example rupee prices instead of dollar prices |
| 3. `useValue` | Exactly the value you write | Settings and fixed values |
| 4. `useFactory` | The value that the function returns | You need code to create the value |
| 5. `useExisting` | The same object as another token: the `LoggerService` object for `OldLogger` | Old code asks for `OldLogger`, and you want it to use `LoggerService` |

The next example uses `useClass`, `useValue` and `useFactory`.

```angular runnable title="useClass, useValue and useFactory"
import { Component, Injectable, inject } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class PriceService {
  label(amount: number) {
    return `$${amount}`;
  }
}

@Injectable()
export class RupeePriceService extends PriceService {
  override label(amount: number) {
    return `₹${amount * 80}`;
  }
}

export class StoreConfig {
  storeName = '';
  freeShippingFrom = 0;
}

@Injectable()
export class Clock {
  hour: number;
  constructor(hour: number) {
    this.hour = hour;
  }
}

@Component({
  selector: 'app-root',
  providers: [
    { provide: PriceService, useClass: RupeePriceService },
    { provide: StoreConfig, useValue: { storeName: 'Gadget Hub', freeShippingFrom: 50 } },
    { provide: Clock, useFactory: () => new Clock(14) },
  ],
  template: `
    <h3>{{ config.storeName }}</h3>
    <p>Mouse: {{ prices.label(15) }}</p>
    <p>Free shipping from {{ prices.label(config.freeShippingFrom) }}</p>
    <p>{{ clock.hour < 12 ? 'Good morning' : 'Good afternoon' }}</p>
  `,
})
export class App {
  prices = inject(PriceService);
  config = inject(StoreConfig);
  clock = inject(Clock);
}
```

What happens in this example:

- The component asks for `PriceService`. The `useClass` provider gives it a `RupeePriceService`, so prices are shown in rupees.
- The `useValue` provider gives the store settings object.
- The `useFactory` provider calls a function that creates a `Clock` with the hour 14.

Delete the `PriceService` line in `providers` and click **Run**. The prices are now shown in dollars.

## `providedIn`

`providedIn` is an option of `@Injectable()`. It adds a provider for the service, so you do not need a `providers` array.

It can have these values:

- **`'root'`:** Angular creates one object for the whole app. Use this in most cases.
- **`'platform'`:** one object is shared by several Angular apps on the same page. This is rarely used.
- **No `providedIn`:** if you write only `@Injectable()`, Angular has no provider for the service. You must add it to a `providers` array. Otherwise, `inject()` throws an error.

Use `providedIn: 'root'` by default. Use `@Injectable()` without `providedIn` only when each component needs its own object of the service. The section "Component-Level Providers" shows this.

## Provider Hierarchy

A **hierarchy** is a structure with levels, like a family tree. Angular has many injectors, and they are arranged in levels that follow the component tree.

### The Levels

- **Root injector:** the top level. It has the `providedIn: 'root'` services and the providers in `app.config.ts`.
- **Component injector:** each component that has a `providers` array gets its own injector.

### How Angular Searches

When a class calls `inject()`, Angular first looks in the injector of the nearest component. If there is no provider there, it looks in the parent component, then the next parent, and so on up to the root. Angular uses the **first** provider it finds.

<figure className="ngc-fig">
<svg viewBox="0 0 640 312" role="img" aria-label="Injector tree for the next example: Root, App with THEME light, Sidebar with THEME dark, and Panel with no providers. Panel's request moves up and finds dark in Sidebar.">
<defs><marker id="ngc-d2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0 0L10 5L0 10z" className="ngc-arrowhead" /></marker></defs><g className="ngc-step ngc-t1"><g className="ngc-node ngc-solid c-purple"><rect x="200" y="8" width="240" height="52" rx="9" /><text x="320.0" y="31" textAnchor="middle" style={{fontSize:"14px"}}>Root injector</text><text className="ngc-sub" x="320.0" y="49" textAnchor="middle">providedIn: 'root' services</text></g></g><g className="ngc-step ngc-t2"><g className="ngc-node ngc-soft c-orange"><rect x="200" y="76" width="240" height="52" rx="9" /><text x="320.0" y="99" textAnchor="middle" style={{fontSize:"14px"}}>App injector</text><text className="ngc-sub" x="320.0" y="117" textAnchor="middle">THEME = 'light'</text></g></g><line className="ngc-link ngc-flow c-slate" x1="320" y1="74" x2="320" y2="62" markerEnd="url(#ngc-d2)" /><g className="ngc-step ngc-t3"><g className="ngc-node ngc-soft c-blue"><rect x="200" y="144" width="240" height="52" rx="9" /><text x="320.0" y="167" textAnchor="middle" style={{fontSize:"14px"}}>Sidebar injector</text><text className="ngc-sub" x="320.0" y="185" textAnchor="middle">THEME = 'dark'</text></g></g><line className="ngc-link ngc-flow c-slate" x1="320" y1="142" x2="320" y2="130" markerEnd="url(#ngc-d2)" /><g className="ngc-step ngc-t4"><g className="ngc-node ngc-soft c-green"><rect x="200" y="212" width="240" height="52" rx="9" /><text x="320.0" y="235" textAnchor="middle" style={{fontSize:"14px"}}>Panel injector</text><text className="ngc-sub" x="320.0" y="253" textAnchor="middle">no providers</text></g></g><line className="ngc-link ngc-flow c-slate" x1="320" y1="210" x2="320" y2="198" markerEnd="url(#ngc-d2)" /><text className="ngc-note" x="460" y="230" textAnchor="start">Panel asks for THEME</text><text className="ngc-note" x="460" y="166" textAnchor="start">Found here: 'dark'</text><text className="ngc-note" x="320" y="300" textAnchor="middle">Angular starts at the component and moves up. It uses the first provider it finds.</text>
</svg>
<figcaption>The injector hierarchy of the next example. The nearest provider wins.</figcaption>
</figure>

In the next example, `App` provides the theme `'light'` and `Sidebar` provides the theme `'dark'`.

```angular runnable title="The nearest provider wins"
import { Component, InjectionToken, inject } from '@angular/core';

export const THEME = new InjectionToken<string>('THEME');

@Component({
  selector: 'app-panel',
  template: `<p>{{ name }} uses the {{ theme }} theme</p>`,
})
export class Panel {
  name = 'Panel';
  theme = inject(THEME);
}

@Component({
  selector: 'app-sidebar',
  providers: [{ provide: THEME, useValue: 'dark' }],
  imports: [Panel],
  template: `<p>Sidebar:</p><app-panel />`,
})
export class Sidebar {}

@Component({
  selector: 'app-root',
  providers: [{ provide: THEME, useValue: 'light' }],
  imports: [Panel, Sidebar],
  template: `<app-panel /><app-sidebar />`,
})
export class App {}
```

The first panel is inside `App` only, so Angular finds the `'light'` provider in `App`. The second panel is inside `Sidebar`, so Angular finds the `'dark'` provider in `Sidebar` first and stops searching.

## Root-Level Providers

A **root-level provider** creates one object that the whole app shares. You can add it in two ways:

```ts
// Way 1: in the service (recommended)
@Injectable({ providedIn: 'root' })
export class AuthService {}

// Way 2: in app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [AuthService],
};
```

- **Use it for:** the signed-in user, the cart, API services, logging and app settings.
- **Benefit:** every component reads the same data.
- **Limitation:** the object stays in memory until the user closes the app. So you must clear private data yourself, for example when the user logs out.

## Component-Level Providers

A **component-level provider** is a service in the `providers` array of a component. Angular creates a new service object for **each copy** of that component on the screen. The child components of that component use the same object.

In the next example, the page shows three `Counter` components. Each one has `providers: [CounterService]`.

```angular runnable title="Each counter gets its own service"
import { Component, Injectable, inject, signal } from '@angular/core';

@Injectable()
export class CounterService {
  readonly count = signal(0);
  increment() {
    this.count.update(n => n + 1);
  }
}

@Component({
  selector: 'app-counter',
  providers: [CounterService],
  template: `
    <p>
      {{ label }}: {{ counter.count() }}
      <button (click)="counter.increment()">+1</button>
    </p>
  `,
})
export class Counter {
  label = 'Counter';
  counter = inject(CounterService);
}

@Component({
  selector: 'app-root',
  imports: [Counter],
  template: `<app-counter /><app-counter /><app-counter />`,
})
export class App {}
```

Each **+1** button changes only its own counter, because each counter has its own `CounterService` object. If `CounterService` used `providedIn: 'root'` and there were no `providers` array, all three counters would show the same number.

| Point | Root-level | Component-level |
|---|---|---|
| Where you add it | `providedIn: 'root'` or `app.config.ts` | The component's `providers` array |
| Number of objects | One for the whole app | One for each copy of the component |
| When Angular creates it | The first time a class asks for it | When Angular creates the component |
| When Angular removes it | When the app closes | When Angular removes the component |
| Example uses | Cart, signed-in user, API service | Data of one form, one editor or one step of a wizard |

## Injection Tokens

A class can be a token. But some values are not classes, for example an API address (a string), a page size (a number) or a settings object. For these values, you create an **`InjectionToken`**.

```ts
export const API_URL = new InjectionToken<string>('API_URL');
```

How to use it:

- The text `'API_URL'` is a description. Angular shows it in error messages.
- To give a value, add a provider: `{ provide: API_URL, useValue: 'https://api.shop.com' }`.
- To read the value, call `inject(API_URL)`.
- You can also give the token a default value with a `factory` function. Then it works without a provider.

```angular runnable title="Configuration with an InjectionToken"
import { Component, InjectionToken, inject } from '@angular/core';

export const API_URL = new InjectionToken<string>('API_URL', {
  providedIn: 'root',
  factory: () => 'https://api.shop.com',
});

export const PAGE_SIZE = new InjectionToken<number>('PAGE_SIZE');

@Component({
  selector: 'app-root',
  providers: [{ provide: PAGE_SIZE, useValue: 20 }],
  template: `
    <p>Products endpoint: {{ apiUrl }}/products</p>
    <p>Page size: {{ pageSize }}</p>
  `,
})
export class App {
  apiUrl = inject(API_URL);
  pageSize = inject(PAGE_SIZE);
}
```

`API_URL` has a default value from its `factory` function. `PAGE_SIZE` has no default value, so the component gives it the value `20` in `providers`.

Do not use a plain string such as `'API_URL'` as a token. Two libraries can use the same string, and then one value replaces the other. Each `InjectionToken` object is different from every other object, so this cannot happen.

## Service Scope

The **scope** of a service is the part of the app that can use one object of the service. The place where you add the provider decides the scope.

- **App scope:** with `providedIn: 'root'`, the whole app uses one object.
- **Component scope:** with `providers: [...]` in a component, that component and its child components use one object. Other parts of the app cannot use it.

### Optional Dependencies

If no provider exists in the scope, `inject()` throws an error. Write `inject(Service, { optional: true })` to get `null` instead of an error.

## Service Lifetime

The **lifetime** of a service is the time between Angular creating the object and Angular removing it.

- **Root service:** Angular creates it the first time a class asks for it. It stays until the user closes the app.
- **Component-level service:** Angular creates it together with its component and removes it together with the component. Before removing it, Angular calls the service's `ngOnDestroy()` method. Write code there to stop timers.

In the next example, `DraftService` is a component-level service of `Editor`. Click **Toggle editor** to remove the editor, and click again to create it.

```angular runnable title="A component-level service is destroyed with its component"
import { Component, Injectable, OnDestroy, inject, signal } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class AuditLog {
  readonly lines = signal<string[]>([]);
  add(line: string) {
    this.lines.update(list => [...list, line]);
  }
}

@Injectable()
export class DraftService implements OnDestroy {
  private log = inject(AuditLog);
  constructor() {
    this.log.add('DraftService created');
  }
  ngOnDestroy() {
    this.log.add('DraftService destroyed');
  }
}

@Component({
  selector: 'app-editor',
  providers: [DraftService],
  template: `<p>Editor is open</p>`,
})
export class Editor {
  draft = inject(DraftService);
}

@Component({
  selector: 'app-root',
  imports: [Editor],
  template: `
    <button (click)="open.set(!open())">Toggle editor</button>
    @if (open()) {
      <app-editor />
    }
    @for (line of log.lines(); track $index) {
      <p>{{ line }}</p>
    }
  `,
})
export class App {
  open = signal(true);
  log = inject(AuditLog);
}
```

`AuditLog` is a root service, so it stays and keeps all the messages. `DraftService` is created each time the editor appears and removed each time the editor disappears.

## Common Mistakes

<div className="ngc-mistakes">

| Mistake | What you see | Fix |
|---|---|---|
| `@Injectable()` without `providedIn` and without a `providers` entry | NullInjectorError: No provider for the service | Add `providedIn: 'root'`, or add the service to `providers` |
| Adding a root service to a component's `providers` too | The component gets its own new object, so the data is not shared | Remove the service from the component's `providers` |
| Using a string as a token | Two values with the same name replace each other | Use `new InjectionToken<T>('...')` |
| Keeping important data in a component-level service | The data is lost when the component is removed | Use a root service for data that must stay |
| Two services that inject each other | Error: circular dependency | Move the shared code into a third service |

</div>

## Check Yourself

## Exercises

## What to Remember

- With DI, a class asks for its dependencies with `inject()`, and Angular gives them. A provider tells Angular how to create a value. The injector creates it once and gives the same object again.
- Angular searches for a provider from the nearest component up to the root. A root provider gives one object for the app. A component provider gives one object for each copy of the component, and Angular removes it with the component.
- Use `useClass`, `useValue` and `useFactory` to choose what a token returns. Use `InjectionToken` for values that are not classes.

Next: **Routing**, how to give each screen its own URL and move between screens.
