Skip to content
⚠️ This article was written in 2019. Some content may be outdated.

Angular Dependency Injection and Service Design

Angular's dependency injection system is at the core of the framework. Understanding it enables you to write more modular, testable code.

Creating a Service ​

typescript
@Injectable({
  providedIn: "root", // global singleton
})
export class UserService {
  private users: User[] = [];

  getUsers(): Observable<User[]> {
    return this.http.get<User[]>("/api/users");
  }
}

Injection Hierarchy ​

typescript
// Module level - shared instance
@NgModule({
  providers: [UserService]
})

// Component level - each component gets its own instance
@Component({
  providers: [UserService]
})

Using InjectionToken ​

typescript
export const API_URL = new InjectionToken<string>('API_URL');

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

// Inject it
constructor(@Inject(API_URL) private apiUrl: string) {}

Testing-Friendly ​

DI makes mocking straightforward:

typescript
TestBed.configureTestingModule({
  providers: [{ provide: UserService, useValue: { getUsers: () => of([]) } }],
});

Angular's DI system is one of the key reasons it is popular in enterprise applications.

MIT Licensed