Skip to main content

Services & Dependency Injection

Basic Service

import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root' // Singleton across app
})
export class UserService {
private users: string[] = [];

getUsers() {
return this.users;
}

addUser(user: string) {
this.users.push(user);
}
}

Inject in Component

import { Component, inject } from '@angular/core';
import { UserService } from './user.service';

@Component({
selector: 'app-user-list',
standalone: true
})
export class UserListComponent {
// Modern inject() function
userService = inject(UserService);

// Or constructor injection (traditional)
constructor(private userService: UserService) {}

users = this.userService.getUsers();
}

Provide Levels

// Root level (singleton)
@Injectable({ providedIn: 'root' })

// Component level (new instance per component)
@Component({
providers: [UserService]
})

// Module level (deprecated with standalone)
@NgModule({
providers: [UserService]
})

Injection Tokens

import { InjectionToken } from '@angular/core';

export const API_URL = new InjectionToken<string>('api.url');

// Provide
@Component({
providers: [
{ provide: API_URL, useValue: 'https://api.example.com' }
]
})

// Inject
apiUrl = inject(API_URL);

Factory Providers

export function userServiceFactory(http: HttpClient) {
return new UserService(http, '/api/users');
}

@Component({
providers: [
{
provide: UserService,
useFactory: userServiceFactory,
deps: [HttpClient]
}
]
})

Best Practices

  • Use providedIn: 'root' for app-wide services
  • Use component providers for component-specific state
  • Prefer inject() over constructor injection (modern)
  • Keep services stateless when possible
  • Use interfaces for abstraction