Belajar Angular - Services & Dependency Injection
Episode 6 of 24

Belajar Angular - Services & Dependency Injection

Episode ini membahas services dan dependency injection: cara membuat service dan meng-inject-nya ke komponen, provider scope di level root, module, dan component, pola singleton service dengan hierarchical injectors, serta interceptor dan provider configuration.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

Sejauh ini data tinggal di dalam komponen. Ketika aplikasi tumbuh, logika bisnis dan data harus dibagikan antar komponen — di sinilah service dan dependency injection (DI) berperan.

Episode 6 membahas cara membuat service dan meng-inject-nya, provider scope di level root, module, dan component, pola singleton dengan hierarchical injectors, serta interceptor dan provider configuration. Konsep DI inilah yang membuat Angular begitu kuat untuk aplikasi enterprise.

Membuat Service dan Inject ke Component

Service Pertama

Service adalah class berdekorator @Injectable yang membungkus logika bisnis dan data yang bisa dibagikan.

Generate service
ng generate service keranjang

Setelah di-generate, isi service dengan state dan method:

JSService keranjang dengan signal
import { Injectable, signal, computed } from '@angular/core';
 
@Injectable({ providedIn: 'root' })
export class KeranjangService {
  private readonly isi = signal<Produk[]>([]);
  readonly totalItem = computed(() => this.isi().length);
  readonly totalHarga = computed(() =>
    this.isi().reduce((akum, p) => akum + p.harga, 0),
  );
 
  tambah(produk: Produk): void {
    this.isi.update((list) => [...list, produk]);
  }
 
  hapus(id: number): void {
    this.isi.update((list) => list.filter((p) => p.id !== id));
  }
}

Service ini menyimpan daftar produk dalam signal, lalu menghitung totalItem dan totalHarga dengan computed. providedIn: 'root' berarti service tersedia di seluruh aplikasi.

Inject ke Component

Karena service disediakan di root, komponen bisa meng-inject-nya lewat fungsi inject:

JSInject service di komponen
import { Component, inject } from '@angular/core';
import { KeranjangService } from './keranjang.service';
 
@Component({
  selector: 'app-header',
  standalone: true,
  template: `<p>Keranjang: {{ keranjang.totalItem() }} item</p>`,
})
export class HeaderComponent {
  private readonly keranjang = inject(KeranjangService);
}

inject(KeranjangService) adalah cara modern menggantikan injection via konstruktor. Angular membuat satu instance service dan memberikan instance yang sama ke semua komponen yang meng-inject-nya.

Provider Scope dan Hierarchical Injectors

Root, Module, dan Component Scope

Provider scope menentukan siapa yang bisa mengakses instance service:

  • providedIn: 'root': satu instance untuk seluruh aplikasi, bahkan untuk lazy-loaded modules.
  • providedIn: 'feature-module': instance dibagikan dalam satu feature module.
  • Provider di level komponen: instance baru dibuat per komponen — cocok untuk state yang tidak boleh dibagikan.
JSProvider di level komponen
@Component({
  selector: 'app-form-item',
  standalone: true,
  providers: [FormStateService],
  template: `...`,
})
export class FormItemComponent {
  private readonly state = inject(FormStateService);
}

providers: [FormStateService] membuat instance baru setiap kali komponen FormItemComponent dibuat. Dua komponen yang sama tidak akan berbagi state — berguna untuk form atau daftar yang saling independen.

Hierarchical Injectors

Injector Angular membentuk hierarki mengikuti struktur komponen. Saat sebuah service di-inject, Angular mencari dari level komponen ke atas hingga menemukan provider-nya. Ini memungkinkan pola shadowing: komponen anak bisa mengganti implementasi service hanya untuk subtree-nya, misalnya menyediakan konfigurasi berbeda untuk fitur tertentu.

Interceptor dan Provider Configuration

Interceptor sebagai Service

Interceptor adalah layanan khusus yang menyelip di antara aplikasi dan HTTP client — cocok untuk menambah header, menangani error, atau logging. Detail lengkapnya di episode 14, tetapi pola provider-nya layak dipahami sejak sekarang:

JSKonfigurasi provider di app.config.ts
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { routes } from './app.routes';
import { provideRouter } from '@angular/router';
 
export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes),
    provideHttpClient(withInterceptors([logInterceptor])),
  ],
};

appConfig di app.config.ts adalah pusat konfigurasi provider aplikasi standalone. provideHttpClient(withInterceptors([...])) mendaftarkan interceptor secara fungsional — pola yang akan kita pakai untuk auth dan error handling.

Penutup

Inti yang harus dibawa pulang:

  • Service adalah class berdekorator @Injectable yang membungkus logika dan data bersama.
  • inject() menggantikan injection via konstruktor di komponen modern.
  • providedIn: 'root' menciptakan singleton untuk seluruh aplikasi.
  • Provider di level komponen membuat instance baru per komponen.
  • Hierarchical injectors memungkinkan shadowing provider per subtree.
  • Provider configuration dipusatkan di app.config.ts lewat fungsi provide*.

Di episode 7 selanjutnya kita akan membahas forms dan validation — membandingkan template-driven dan reactive forms, memakai FormControl, FormGroup, dan FormArray, menyusun validasi built-in dan custom, serta membangun dynamic forms dengan feedback pengguna yang baik.