Jump into concepts and practice - no test required
or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Service-based State Management in Angular
📖 Scenario: You are building a simple Angular app to manage a list of favorite movies. You want to keep the list of movies in one place so that different parts of your app can access and update it easily.
🎯 Goal: Create an Angular service to hold the list of favorite movies and allow components to add new movies and get the current list.
📋 What You'll Learn
Create a service called MovieService with a private array of movies
Add a method getMovies() that returns the current list of movies
Add a method addMovie(movie: string) to add a new movie to the list
Use Angular's @Injectable decorator with providedIn: 'root'
Create a component that uses MovieService to display and add movies
💡 Why This Matters
🌍 Real World
Service-based state management is common in Angular apps to share data between components without repeating code or using complex state libraries.
💼 Career
Understanding how to create and use services for state management is a key skill for Angular developers working on real-world applications.
Progress0 / 4 steps
1
Create the MovieService with initial movie list
Create a service called MovieService with a private array movies containing these exact strings: 'Inception', 'The Matrix', and 'Interstellar'. Use @Injectable({ providedIn: 'root' }) decorator.
Angular
Hint
Use @Injectable from @angular/core and create a private array called movies with the exact movie names.
2
Add getMovies method to MovieService
Add a public method called getMovies() in MovieService that returns the movies array.
Angular
Hint
Write a method getMovies() that returns the private movies array.
3
Add addMovie method to MovieService
Add a public method called addMovie(movie: string) in MovieService that adds the movie string to the movies array.
Angular
Hint
Write a method addMovie that takes a string and adds it to the movies array using push.
4
Create a component to use MovieService
Create a component class called MovieListComponent that injects MovieService in its constructor. Add a public property movies initialized by calling getMovies() from the service. Add a method addNewMovie(movie: string) that calls addMovie(movie) on the service and updates movies by calling getMovies() again.
Angular
Hint
Create a component class that injects MovieService in the constructor. Initialize movies by calling getMovies(). Add a method addNewMovie that calls addMovie and updates movies.
Practice
(1/5)
1. What is the main benefit of using a service for state management in Angular?
easy
A. It allows sharing state easily across multiple components.
B. It automatically updates the UI without any coding.
C. It replaces the need for components entirely.
D. It makes the app run faster by skipping change detection.
Solution
Step 1: Understand service role in Angular
Services hold data and logic separate from components.
Step 2: Recognize state sharing benefit
Services can be injected into many components, sharing the same state instance.
Final Answer:
It allows sharing state easily across multiple components. -> Option A
Quick Check:
Service-based state management = shared state [OK]
Hint: Services share data across components easily [OK]
Common Mistakes:
Thinking services replace components
Believing services auto-update UI without code
Assuming services speed up app by skipping detection
2. Which decorator and property make an Angular service a singleton across the app?
easy
A. @NgModule({ providers: [] })
B. @Component({ selector: 'app-root' })
C. @Directive({ selector: '[appService]' })
D. @Injectable({ providedIn: 'root' })
Solution
Step 1: Identify Angular service decorator
@Injectable marks a class as a service for dependency injection.
Step 2: Understand providedIn property
Setting providedIn: 'root' makes the service a singleton app-wide.
Final Answer:
@Injectable({ providedIn: 'root' }) -> Option D
Quick Check:
Singleton service = @Injectable with providedIn root [OK]
Hint: Use @Injectable({ providedIn: 'root' }) for singleton services [OK]
Common Mistakes:
Confusing @Component with service decorator
Using @NgModule providers without providedIn
Mistaking @Directive for service declaration
3. Given this service code, what will the console log after calling increment() twice?
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class CounterService {
count = signal(0);
increment() {
this.count.update(c => c + 1);
}
}
const service = new CounterService();
service.increment();
service.increment();
console.log(service.count());
medium
A. 1
B. 0
C. 2
D. undefined
Solution
Step 1: Understand initial signal value
The signal count starts at 0.
Step 2: Apply two increments
Each increment adds 1, so after two calls, count is 2.
Final Answer:
2 -> Option C
Quick Check:
0 + 1 + 1 = 2 [OK]
Hint: Each update adds 1; two calls add 2 total [OK]
Common Mistakes:
Forgetting to call the signal as a function to get value
Assuming count resets after each increment
Confusing update with set method
4. What is wrong with this Angular service code for state management?
import { Injectable, signal } from '@angular/core';
@Injectable()
export class DataService {
data = signal([]);
addItem(item: string) {
this.data().push(item);
}
}
medium
A. The service is missing providedIn: 'root' for singleton scope.
B. The signal value is mutated directly, which breaks reactivity.
C. The addItem method should return the updated array.
D. The signal should be initialized with null, not an empty array.
Solution
Step 1: Check signal mutation method
The code calls this.data() to get the array, then pushes directly.
Step 2: Understand signal immutability
Directly mutating the array breaks Angular's reactivity; must use update() or set() to replace value.
Final Answer:
The signal value is mutated directly, which breaks reactivity. -> Option B
Quick Check:
Mutate signal value immutably to keep reactivity [OK]
Hint: Never mutate signal value directly; use update or set [OK]
Common Mistakes:
Ignoring providedIn for singleton scope
Expecting addItem to return value
Thinking null is better initial value than []
5. You want to share a list of tasks across components using a service with Angular signals. Which approach correctly updates the tasks list immutably when adding a new task?
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class TaskService {
tasks = signal([]);
addTask(newTask: string) {
// Which line correctly updates tasks?
}
}
hard
A. this.tasks.set([...this.tasks(), newTask]);
B. this.tasks = signal([...this.tasks(), newTask]);
C. this.tasks().push(newTask);
D. this.tasks.update(tasks => { tasks.push(newTask); return tasks; });
Solution
Step 1: Understand immutable update with signals
Signals require replacing the value immutably to trigger updates.
Step 2: Analyze options for correct update
this.tasks.set([...this.tasks(), newTask]); uses set() with a new array including the new task, which is correct.
Final Answer:
this.tasks.set([...this.tasks(), newTask]); -> Option A
Quick Check:
Immutable update with set() = correct pattern [OK]
Hint: Use set() with new array copy to update signals immutably [OK]
Common Mistakes:
Mutating array inside update without returning new array
Directly pushing to signal value
Reassigning signal variable instead of updating value