Dependency Injection Basics

Back

Loading concept...

Dependency Injection Basics in Angular

The Restaurant Kitchen Analogy 🍳

Imagine you own a restaurant. Your chefs need ingredients to cook meals. Now, there are two ways to get ingredients:

The Hard Way: Each chef goes to the market, picks ingredients, carries them back, and manages everything themselves. Exhausting, right?

The Smart Way: You hire a delivery service. Chefs just say what they need, and ingredients magically appear! The delivery service handles everything.

Dependency Injection (DI) is like that delivery service. Your Angular components just ask for what they need, and Angular delivers it. No hunting. No hassle.


What is Dependency Injection?

Simple Definition: Dependency Injection is a way for your code to ask for things it needs, instead of creating them itself.

Think of it like this:

  • Without DI: “I’ll build my own bicycle from scratch every time I need to ride.”
  • With DI: “Someone hands me a bicycle when I need it.”

Why Does This Matter?

Without DI With DI
Components create their own helpers Angular creates helpers and delivers them
Hard to test Easy to test
Changes ripple everywhere Changes stay contained
Tight coupling Loose coupling

Real Example

Without DI (The Hard Way):

class Chef {
  private ingredient = new Tomato();
  // Chef creates its own tomato
  // What if we want onion instead?
  // We must change the Chef class!
}

With DI (The Smart Way):

class Chef {
  constructor(
    private ingredient: Vegetable
  ) {}
  // Angular delivers whatever
  // vegetable we configure!
}

The Injectable Decorator

What is @Injectable()?

The @Injectable() decorator is like a name tag at a party. It tells Angular: “Hey! I’m available to be delivered to anyone who needs me!”

Without this name tag, Angular wouldn’t know this class exists for delivery.

The Syntax

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class DeliveryService {
  deliverFood() {
    return 'Pizza is here! 🍕';
  }
}

Breaking It Down

graph TD A["@Injectable#40;#41;"] --> B["Tells Angular: I can be injected"] B --> C["providedIn: 'root'"] C --> D["Available everywhere in the app"]

Key Points:

  • @Injectable() = “I’m available for delivery”
  • Without it = Angular ignores the class
  • It’s a decorator (special function that adds powers)

providedIn Options

Remember our delivery service? Now let’s decide where the delivery truck can go!

Option 1: ‘root’ (Everywhere!)

@Injectable({
  providedIn: 'root'
})
export class GlobalService { }

What it means: This service is available everywhere in your app. Like a pizza chain with delivery to every neighborhood!

Use when: You want the same service instance across your entire application.

Option 2: ‘platform’ (Multiple Apps)

@Injectable({
  providedIn: 'platform'
})
export class SharedService { }

What it means: Shared across multiple Angular apps on the same page. Rare, but useful!

Option 3: ‘any’ (Fresh Each Time)

@Injectable({
  providedIn: 'any'
})
export class FreshService { }

What it means: Each lazy-loaded module gets its own fresh copy. Like each restaurant location making their own fresh dough!

Option 4: A Specific Module

@Injectable({
  providedIn: OrdersModule
})
export class OrderService { }

What it means: Only available in that specific module. Like a local bakery that only delivers to one neighborhood.

Quick Reference

providedIn Scope Use Case
'root' Whole app Most services
'platform' Multiple apps Micro-frontends
'any' Per lazy module Module-specific state
SomeModule That module only Feature-specific

Services: Your Helpful Assistants

What is a Service?

A service is a class that does a specific job. Think of services like specialists in a hospital:

  • Doctor → handles diagnoses
  • Nurse → handles patient care
  • Pharmacist → handles medications

In Angular:

  • AuthService → handles login/logout
  • DataService → handles API calls
  • LoggerService → handles logging

Creating a Service

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class CalculatorService {

  add(a: number, b: number): number {
    return a + b;
  }

  subtract(a: number, b: number): number {
    return a - b;
  }
}

Using a Service in a Component

import { Component } from '@angular/core';
import { CalculatorService } from './calculator.service';

@Component({
  selector: 'app-math',
  template: `<p>5 + 3 = {{ result }}</p>`
})
export class MathComponent {
  result: number;

  constructor(private calc: CalculatorService) {
    this.result = this.calc.add(5, 3);
  }
}

The Magic Moment

Notice we didn’t write:

private calc = new CalculatorService();

We just asked for it in the constructor, and Angular delivered it! That’s DI in action!

graph TD A["MathComponent needs CalculatorService"] --> B["Angular checks: Is CalculatorService injectable?"] B --> C["Yes! @Injectable decorator found"] C --> D["Angular creates or finds instance"] D --> E["Delivers to MathComponent constructor"]

Singleton Services: One for All

The Problem

Imagine if every time someone ordered coffee at a cafe, they got a brand new coffee machine. Wasteful, right?

The Solution: Singletons

A singleton is a single shared instance. One coffee machine serves everyone!

How Angular Does It

When you use providedIn: 'root':

@Injectable({
  providedIn: 'root'  // 👈 Makes it singleton!
})
export class CartService {
  items: string[] = [];

  addItem(item: string) {
    this.items.push(item);
  }
}

Every component gets the SAME CartService!

Seeing It in Action

// Component A adds an item
this.cartService.addItem('Apple');

// Component B sees the same cart
console.log(this.cartService.items);
// Output: ['Apple']
// 👆 Same instance, shared data!

Why Singletons Rock

Benefit Explanation
Shared State All components see the same data
Memory Efficient One instance, not hundreds
Consistent No confusion about which instance has what

Non-Singleton Example

If you want a fresh instance per component:

@Component({
  selector: 'app-special',
  providers: [FreshService]  // 👈 New instance!
})
export class SpecialComponent { }

This creates a new FreshService just for SpecialComponent and its children.


Putting It All Together

Let’s build a complete example!

Step 1: Create the Service

// user.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  private currentUser = 'Guest';

  login(name: string) {
    this.currentUser = name;
  }

  getUser(): string {
    return this.currentUser;
  }
}

Step 2: Use in Components

// header.component.ts
@Component({
  selector: 'app-header',
  template: `<h1>Hello, {{ userName }}</h1>`
})
export class HeaderComponent {
  userName: string;

  constructor(private userService: UserService) {
    this.userName = userService.getUser();
  }
}
// login.component.ts
@Component({
  selector: 'app-login',
  template: `
    <button (click)="login()">
      Login as Alice
    </button>
  `
})
export class LoginComponent {
  constructor(private userService: UserService) {}

  login() {
    this.userService.login('Alice');
  }
}

The Flow

graph TD A["UserService created once"] --> B["HeaderComponent asks for it"] A --> C["LoginComponent asks for it"] B --> D["Both get SAME instance"] C --> D D --> E["Shared user state!"]

Key Takeaways 🎯

  1. Dependency Injection = Angular delivers what your code needs
  2. @Injectable() = “I’m available for delivery” decorator
  3. providedIn: ‘root’ = Available everywhere as singleton
  4. Services = Specialist classes that do specific jobs
  5. Singletons = One shared instance for everyone

The Golden Rule

Don’t create dependencies yourself. Let Angular deliver them!

Before DI:

private service = new MyService(); // ❌ Hard way

With DI:

constructor(private service: MyService) {} // ✅ Smart way

You Did It! 🎉

You now understand how Angular’s Dependency Injection works! You’re like a restaurant owner who just discovered delivery services — your kitchen (code) will never be the same!

Remember: Your components are the chefs. Services are the ingredients. Angular’s DI is the delivery truck. Now go build something delicious! 🚀

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.