A service declares what it needs, and Angular's injector supplies it. With constructor injection, you list the other service as a constructor parameter.
@Injectable({
providedIn: 'root'
})
export class LoggerService {
log(message: string): void {
console.log(message);
}
}
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private logger: LoggerService) {}
getData(): any[] {
this.logger.log('Getting data...');
return [];
}
}
Angular reads the parameter type, finds the provider for LoggerService, and passes the instance in when it creates DataService. Both services are root-provided, so the whole app shares one logger.
The style guide now prefers the inject() function, which reads better when a class has many dependencies. You write private logger = inject(LoggerService); in a field initializer or call it in the constructor.
Avoid circular dependencies, where service A depends on service B and service B depends on A as well. Angular cannot create either one and throws an error.
This answer doesn't lend itself to a diagram - it reads best . No credits were charged.
Why there's no diagram: “”
The interactive diagram is below the answer - jump to diagram ↓ · Below it, the related concept . Jump to it ↓
The diagram below the answer is the concept . Jump to it ↓