@Injectable and the DI System
Angular uses dependency injection (DI) to supply services to the components and other services that need them. Instead of components creating their own service instances with new, Angular creates services and injects them automatically.
@Injectable
Section titled “@Injectable”A service is a plain TypeScript class marked with the @Injectable decorator:
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root'})export class MovieService { // methods here}The @Injectable decorator has one important option: providedIn. Setting it to 'root' tells Angular to create one instance of this service and make it available throughout the entire application. This is called a root-level singleton.
How Angular resolves dependencies
Section titled “How Angular resolves dependencies”When a component declares a dependency:
export class Home { constructor(private movieService: MovieService) {}}Angular’s DI system:
- Looks at the constructor parameter type:
MovieService - Finds the service registered with
providedIn: 'root' - Returns the existing singleton instance (or creates it if this is the first request)
- Assigns it to
this.movieService
You never call new MovieService(). Angular manages the lifecycle.
Why this matters
Section titled “Why this matters”Testing: In tests, you can provide a mock service instead of the real one. The component under test receives the mock automatically.
Singleton state: Every component that injects WatchlistService gets the same instance. When one component modifies the watchlist, all others see the updated state immediately.
Decoupling: Components do not know how services are constructed. If MovieService starts needing HttpClient, you add that dependency to MovieService — the components that use it are unaffected.
Services injecting other services
Section titled “Services injecting other services”Services can depend on other services the same way components do:
@Injectable({ providedIn: 'root' })export class MovieService { constructor(private http: HttpClient) {}
getPopular(): Observable<MoviesResponse> { return this.http.get<MoviesResponse>(`${BASE_URL}/movie/popular`, { params: { api_key: API_KEY } }); }}HttpClient is Angular’s built-in HTTP service. MovieService declares it as a constructor dependency, and Angular injects it automatically — the same way components inject MovieService.
The injector tree
Section titled “The injector tree”Angular maintains an injector tree — a hierarchy of containers that hold service instances. The root injector holds root-level services. Feature-level injectors can hold services scoped to a specific part of the app.
For this course, providedIn: 'root' is sufficient for all services. You do not need to configure the injector tree manually.
Exercise
Section titled “Exercise”- Generate a service:
ng generate service services/logger. - Open the generated file. Notice
@Injectable({ providedIn: 'root' }). - Add a
log(message: string): void { console.log('[Logger]', message); }method. - Inject
LoggerServiceintoAppComponent’s constructor and callthis.logger.log('App initialized')inngOnInit. - Run the app and confirm the log message appears in the browser console.
@Injectable({ providedIn: 'root' })registers a service as a root-level singleton — one instance for the whole app.- Angular’s DI system reads constructor parameter types and injects the matching service instances automatically.
- Services can inject other services the same way components do.
- Root-level singletons share state across all components that inject them.
- The
providedIn: 'root'pattern is the right default for all services in this course.