Creating and Injecting a Service
You know what services are and why they exist. Now let’s create one and use it.
Generating a service
Section titled “Generating a service”Use the CLI to generate a service:
ng generate service services/movieShort form:
ng g s services/movieThis creates two files:
src/app/services/├── movie.service.ts ← the service class└── movie.service.spec.ts ← the unit testThe generated movie.service.ts:
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root'})export class MovieService {}Constructor injection
Section titled “Constructor injection”The classic way to inject a service is via the constructor:
import { Component, OnInit } from '@angular/core';import { MovieService } from '../../services/movie.service';import { Movie } from '../../models/movie.model';
@Component({ selector: 'app-home', standalone: true, templateUrl: './home.html', styleUrl: './home.css'})export class Home implements OnInit { movies: Movie[] = [];
constructor(private movieService: MovieService) {}
ngOnInit(): void { this.movieService.getPopular().subscribe(movies => { this.movies = movies; }); }}Angular sees MovieService in the constructor parameter list and injects the singleton instance before ngOnInit runs.
The inject() function — modern alternative
Section titled “The inject() function — modern alternative”Angular 14+ provides a functional alternative to constructor injection: inject(). It retrieves a service from the DI system without requiring a constructor parameter:
import { Component, OnInit, inject } from '@angular/core';import { MovieService } from '../../services/movie.service';
@Component({ /* ... */ })export class Home implements OnInit { private movieService = inject(MovieService); movies: Movie[] = [];
ngOnInit(): void { this.movieService.getPopular().subscribe(movies => { this.movies = movies; }); }}inject() must be called during class field initialization or inside a function that runs in an injection context (like ngOnInit of a component, or the body of a guard function). It cannot be called asynchronously.
Which style to use?
Section titled “Which style to use?”Both constructor injection and inject() are valid. In CinemaVault:
- Components use
inject()— it avoids constructor boilerplate when a class only injects services - Guards use
inject()— guards are plain functions, so there is no constructor option
Choose whichever reads more clearly in context. Either way, Angular’s DI system supplies the same singleton instance.
A complete example
Section titled “A complete example”Here is a MovieService with a getPopular() method, and a Home component that uses it:
import { Injectable, inject } from '@angular/core';import { HttpClient } from '@angular/common/http';import { Observable, map } from 'rxjs';
@Injectable({ providedIn: 'root' })export class MovieService { private http = inject(HttpClient); private readonly base = 'https://api.themoviedb.org/3';
getPopular(): Observable<Movie[]> { return this.http.get<MoviesResponse>(`${this.base}/movie/popular`, { params: { api_key: API_KEY } }).pipe(map(res => res.results)); }}@Component({ /* ... */ })export class Home implements OnInit { private movieService = inject(MovieService); movies: Movie[] = []; loading = true;
ngOnInit(): void { this.movieService.getPopular().subscribe({ next: movies => { this.movies = movies; this.loading = false; }, error: () => { this.loading = false; } }); }}Exercise
Section titled “Exercise”- Generate
ng g s services/greeting. - Add a
getGreeting(name: string): string { return 'Hello, ' + name + '!'; }method. - Inject
GreetingServiceintoAppComponentusinginject(). - Display the result in the template:
{{ greeting }}wheregreeting = this.greetingService.getGreeting('Angular'). - Try both
inject()and constructor injection and confirm both produce the same result.
- Generate services with
ng generate service services/name. - Constructor injection:
constructor(private myService: MyService) {}— Angular injects the singleton automatically. inject()function:private myService = inject(MyService)— a modern alternative without constructor boilerplate.- Services injected with
inject()must be called during class initialization or within an injection context. - Both approaches provide the same singleton instance from Angular’s DI system.