Codecademy Logo

Angular Services and Dependency Injection

Services in Angular

In Angular, services encapsulate reusable functionality, allowing for centralized logic that can be shared across multiple components. This promotes better code organization and maintainability and reduces redundancy within the application.

@Injectable decorator in Angular

The @Injectable decorator designates a class as a service in Angular, allowing Angular to manage its creation and distribution.

import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class MyService {
// Service logic
}

The providedIn property in Angular

The providedIn property in Angular is used to specify where a service should be provided, determining its scope within the application.

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

Values of ProvidedIn in Angular

In Angular, setting providedIn: 'root' in the @Injectable decorator registers the service with the root injector, making it available throughout the entire application as a single shared instance. This ensures the service can be accessed globally and benefits from tree-shaking to optimize the application’s bundle size.

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

Manually Providing Services in Angular

In Angular, when providedIn is set to null or not specified in the @Injectable decorator, the service must be manually provided in a module or component’s providers array to make it available. This approach is useful for scoping services to specific components or modules.

// Service File
@Injectable()
export class MyService { }
// Component File
@Component({
selector: 'app-user',
providers: [MyService],
template: `<p>User Component</p>`,
})
export class UserComponent {}

Injecting Services in Angular

In Angular, services can be injected into components through constructor injection or the inject() method. Constructor injection adds the service as a parameter in the component’s constructor, while the inject() method directly injects the service within the component’s class body.

@Component({
standalone: true,
selector: 'app-example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
export class ExampleComponent {
// constructor injection
constructor(private authService: AuthService) {}
// inject() method
private loggingService = inject(LoggingService);
ngOnInit() {
this.authService.login();
this.loggingService.log('User logged in.');
}
}

Injecting Services into Other Services

In Angular, services can be injected into other services to centralize logic and promote modularity. This is achieved using constructor injection or the inject() method, allowing one service to depend on another while maintaining separation of concerns.

@Injectable({
providedIn: 'root',
})
export class LoggerService {
log(message: string) {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] ${message}`);
}
}
@Injectable({
providedIn: 'root',
})
export class DataService {
private loggerService = inject(LoggerService);
fetchData() {
this.loggerService.log('Fetching data...');
// Logic to fetch data
}
}

Angular’s dependency injection system

Angular’s dependency injection system is hierarchical, allowing injectors to be nested within each other in a tree-like structure.

Root Injector
├── AppComponent Injector
│ ├── HeaderComponent Injector
│ ├── SidebarComponent Injector
│ └── ContentComponent Injector
│ ├── ChildComponent Injector
│ └── AnotherChildComponent Injector

Injector bubbling in Angular

In Angular, injector bubbling is the process by which Angular moves up the injector hierarchy to resolve a dependency. If a service isn’t found in the current injector, Angular searches the parent injector, continuing up the hierarchy until the service is found or the root injector is reached.

Root Injector
└── AppComponent Injector
└── ChildComponent Injector

Instance of Services

In Angular, when a service is provided at the component level, a new instance of the service is created for each instance of the component.

Shared Services

In Angular, when a service is provided at the component level, it is shared by that component and all of its descendant components. If a descendant component re-provides the service, it creates its own instance, overriding the shared instance from the parent component.

Dependency Injection in Angular

In Angular, dependency injection (DI) is a design pattern that allows the creation and distribution of service instances to components and other services. This decouples components from creating their dependencies, enhancing flexibility, testability, and maintainability by allowing them to be easily injected and managed.

Learn More on Codecademy