Services & Dependency Injection
5 questions foundWhat is a service in Angular and why are services used to hold shared logic?
Beginner A service is a class dedicated to a specific piece of functionality, such as fetching data from a server or managing shared application state, kept separate from components so that logic can be reused across many different components without duplicating code.
@Injectable({ providedIn: 'root' })
export class UserService {
getUsers() {
return this.http.get('/api/users');
}
constructor(private http: HttpClient) {}
}
Real-world example Several completely different components across an app all use the same UserService to fetch user data, avoiding the need for each component to duplicate that same fetching logic on its own.
Common follow-ups: Why should components generally avoid containing complex business logic themselves?;What does the Injectable decorator actually do?
Components & Templates;Dependency Injection Providers & Injection Tokens
What is dependency injection in Angular, and how does a component receive a service?
Beginner Dependency injection means a component or another service does not create its own dependencies directly, but instead receives them automatically, usually through its constructor, from Angular's injection system, which handles creating and providing the correct shared instance.
@Component({ selector: 'app-user-list' })
export class UserListComponent {
constructor(private userService: UserService) {}
ngOnInit() {
this.userService.getUsers().subscribe((users) => this.users = users);
}
}
Real-world example A user list component simply asks for a UserService in its constructor, and Angular automatically provides the correct shared instance, without the component needing to know anything about how that service was actually created.
Common follow-ups: What happens if Angular cannot find a provider for a requested dependency?;How does dependency injection make it easier to test a component in isolation?
Testing with Jasmine & Karma;Dependency Injection Providers & Injection Tokens
How does the newer inject function differ from using constructor based dependency injection in Angular?
Intermediate The inject function lets you request a dependency directly inside a property initializer or a function, rather than only inside a constructor, which can make code more concise, especially for standalone functions like route guards and resolvers that do not have a class constructor to use.
import { inject } from '@angular/core';
export class UserListComponent {
private userService = inject(UserService);
ngOnInit() {
this.userService.getUsers().subscribe((users) => this.users = users);
}
}
Real-world example A route guard function, which has no constructor of its own, uses the inject function to access the AuthService directly, something that would not have been possible using only traditional constructor based injection.
Common follow-ups: Where exactly can the inject function be called, and where is it not allowed?;Is there any practical difference in behavior between inject and constructor injection inside a component?
Router Guards & Resolvers;Standalone Components
What is hierarchical dependency injection in Angular, and how does providing a service at the component level differ from providing it at the root level?
Advanced Angular's injector system is hierarchical, meaning a service provided inside a specific component's providers array creates a new, separate instance just for that component and its children, rather than sharing the single application wide instance created when a service is provided at the root level. This lets different parts of an app have their own isolated instance of the same service when needed.
@Component({
selector: 'app-shopping-cart',
providers: [CartService] // a new, separate instance just for this component and its children
})
export class ShoppingCartComponent {}
Real-world example A product comparison page needs a completely separate, isolated instance of a comparison service for each individual comparison widget on the page, achieved by providing that service at the component level instead of the root level.
Common follow-ups: How do you decide whether a service should be provided at the root level or a specific component level?;What happens to a component level service instance when that component is destroyed?
Dependency Injection Providers & Injection Tokens;NgModules & Modular Architecture
How would you mock a service during testing to isolate a component from its real dependencies?
Intermediate You provide a fake, simplified version of the service in your test's configuration, replacing the real one, letting you control exactly what data or behavior the component receives during the test without depending on a real backend or complex real service logic.
TestBed.configureTestingModule({
providers: [{ provide: UserService, useValue: { getUsers: () => of([{ name: 'Test User' }]) } }]
});
Real-world example A component test replaces the real UserService, which normally makes a network request, with a simple mock object returning predictable fake data, letting the test run quickly and reliably without depending on any real backend.
Common follow-ups: What is the difference between mocking a service with useValue versus using a spy object?;Why is isolating a component from its real dependencies considered good testing practice?
Testing with Jasmine & Karma;Dependency Injection Providers & Injection Tokens