Introduction
Dependency Injection (DI) is a design pattern used to implement IoC (Inversion of Control), allowing a class to receive its dependencies from an external source rather than creating them itself. In Angular, DI is a core concept that enables efficient management of dependencies, making your code more modular, testable, and maintainable.
Key Concepts
- Dependency: An object that another object depends on.
- Injector: A service locator that provides dependencies to classes.
- Provider: An object that tells the injector how to obtain or create a dependency.
- Token: A key used to map a dependency to a provider.
How Dependency Injection Works in Angular
- Registering Providers: You register providers in Angular's dependency injection system, typically in the
@NgModule
decorator or in the@Injectable
decorator. - Injecting Dependencies: Angular injects the dependencies into the constructor of the class where they are needed.
Practical Example
Step 1: Creating a Service
First, let's create a simple service that we will inject into a component.
// src/app/logger.service.ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class LoggerService { log(message: string) { console.log(message); } }
Step 2: Injecting the Service into a Component
Next, we will inject this service into a component.
// src/app/app.component.ts import { Component, OnInit } from '@angular/core'; import { LoggerService } from './logger.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { constructor(private logger: LoggerService) {} ngOnInit() { this.logger.log('AppComponent initialized'); } }
Step 3: Registering the Service
In this example, the LoggerService
is provided in the root injector by using the providedIn: 'root'
syntax in the @Injectable
decorator. This means the service is available application-wide.
Common Mistakes and Tips
- Forgetting to Register the Service: Ensure that your service is registered either in the
@NgModule
providers array or usingprovidedIn: 'root'
in the@Injectable
decorator. - Circular Dependencies: Be cautious of circular dependencies, where two or more services depend on each other, leading to an infinite loop.
- Singleton Services: By default, services provided in the root injector are singletons. If you need multiple instances, provide the service in a component or a module.
Exercise
Task
Create a new service called DataService
that fetches data and inject it into a component to display the data.
Solution
- Create the Service
// src/app/data.service.ts import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class DataService { getData() { return ['Data 1', 'Data 2', 'Data 3']; } }
- Inject the Service into a Component
// src/app/app.component.ts import { Component, OnInit } from '@angular/core'; import { DataService } from './data.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { data: string[]; constructor(private dataService: DataService) {} ngOnInit() { this.data = this.dataService.getData(); } }
- Display the Data in the Template
Conclusion
In this section, we covered the basics of Dependency Injection in Angular, including how to create and inject services. We also discussed common mistakes and provided a practical exercise to reinforce the concepts. Understanding DI is crucial for building scalable and maintainable Angular applications. In the next section, we will delve into Hierarchical Injectors, which allow for more advanced dependency management.
Angular 2+ Course
Module 1: Introduction to Angular
Module 2: TypeScript Basics
- Introduction to TypeScript
- TypeScript Variables and Data Types
- Functions and Arrow Functions
- Classes and Interfaces