Tutorial lengkap belajar Angular dari nol — components, services, routing, RxJS, dependency injection, dan best practices untuk membangun aplikasi enterprise yang scalable
Angular adalah framework web yang dikembangkan oleh Google dan pertama kali dirilis pada tahun 2016 sebagai versi rewrite dari AngularJS. Angular menggunakan TypeScript sebagai bahasa utama dan dirancang khusus untuk membangun aplikasi web enterprise yang kompleks, scalable, dan mudah di-maintain.
Berbeda dengan library seperti React yang hanya menangani view layer, Angular bersifat opinionated full framework yang menyediakan semua tools yang dibutuhkan: routing, form handling, HTTP client, testing, dan banyak lagi — semuanya terintegrasi dalam satu paket.
Mengapa Memilih Angular?
Keunggulan
Penjelasan
TypeScript Native
Angular dibangun dengan TypeScript yang menyediakan type safety, autocompletion, dan refactoring yang lebih baik
Full Framework
Semua tools sudah tersedia dari awal — routing, HTTP, forms, testing, i18n
Dependency Injection
Sistem DI bawaan yang powerful untuk mengelola dependencies antar komponen
CLI yang Powerful
Angular CLI memudahkan generate components, services, testing, dan build production
Enterprise Ready
Banyak digunakan di perusahaan besar seperti Google, Microsoft, Deutsche Bank
RxJS Integration
Dukungan reactive programming bawaan untuk menangani async operations
Angular vs Framework Lain
Aspek
Angular
React
Vue.js
Tipe
Full Framework
Library
Framework
Bahasa
TypeScript
JSX/TSX
JavaScript/Template
Ukuran
~143 KB (gzip)
~42 KB (gzip)
~33 KB (gzip)
Learning Curve
🔴 Curam
🟡 Sedang
🟢 Mudah
State Management
NgRx / Services / Signals
Redux / Zustand
Vuex / Pinia
DOM
Incremental DOM
Virtual DOM
Virtual DOM
Cocok untuk
Enterprise, Banking, SPA besar
SPA, Mobile App
SPA kecil-sedang
Diagram: Angular Application Architecture
💡 Angular vs AngularJS
Jangan bingung antara Angular (v2+ sampai v17+) dan AngularJS (v1.x). Angular adalah rewrite total yang menggunakan TypeScript, component-based architecture, dan performa jauh lebih baik. AngularJS sudah deprecated sejak Desember 2021.
2. Setup dan Instalasi Angular CLI
Untuk memulai dengan Angular, kita perlu menginstal Angular CLI (Command Line Interface) yang merupakan tool resmi untuk membuat, mengembangkan, dan mem-build aplikasi Angular.
Prasyarat
Node.js versi 18.13 atau lebih baru
npm versi 8 atau lebih baru (sudah terinstal bersama Node.js)
Text Editor — VS Code sangat direkomendasikan dengan extension Angular Language Service
Instalasi Angular CLI
Diagram
⚠️ Standalone Components (Angular 17+)
Sejak Angular 14+, Angular mendukung standalone components yang tidak memerlukan NgModule. Mulai Angular 15-17, standalone menjadi default. Dalam tutorial ini kita menggunakan pendekatan standalone terbaru.
3. Memahami Components
Components adalah blok bangunan utama dari setiap aplikasi Angular. Setiap component terdiri dari tiga bagian utama: template (HTML), class (TypeScript), dan styles (CSS/SCSS).
Membuat Component
Diagram
Anatomi Component
Diagram
Membuat dan Menggunakan Service
bash
Diagram
typescript
// product.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject, catchError, throwError } from 'rxjs';
export interface Product {
id: number;
name: string;
price: number;
category: string;
stock: number;
}
@Injectable({
providedIn: 'root' // Singleton tersedia di seluruh app
})
export class ProductService {
private apiUrl = 'https://api.example.com/products';
// BehaviorSubject untuk menyimpan state
private productsSubject = new BehaviorSubject<Product[]>([]);
public products$ = this.productsSubject.asObservable();
constructor(private http: HttpClient) {}
// GET semua produk
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>(this.apiUrl).pipe(
catchError(this.handleError)
);
}
// GET produk berdasarkan ID
getProductById(id: number): Observable<Product> {
return this.http.get<Product>(`${this.apiUrl}/${id}`).pipe(
catchError(this.handleError)
);
}
// POST produk baru
createProduct(product: Omit<Product, 'id'>): Observable<Product> {
return this.http.post<Product>(this.apiUrl, product).pipe(
catchError(this.handleError)
);
}
// PUT update produk
updateProduct(id: number, product: Partial<Product>): Observable<Product> {
return this.http.put<Product>(`${this.apiUrl}/${id}`, product).pipe(
catchError(this.handleError)
);
}
// DELETE produk
deleteProduct(id: number): Observable<void> {
return this.http.delete<void>(`${this.apiUrl}/${id}`).pipe(
catchError(this.handleError)
);
}
// Error handler
private handleError(error: any): Observable<never> {
console.error('API Error:', error);
return throwError(() => new Error(
error.message || 'Terjadi kesalahan pada server'
));
}
}
Providing Services — Level yang Berbeda
typescript
// 1. Root level (singleton di seluruh app)
@Injectable({ providedIn: 'root' })
export class GlobalService { }
// 2. Module level (singleton di dalam module)
@NgModule({
providers: [ModuleService]
})
export class FeatureModule { }
// 3. Component level (instance baru per component)
@Component({
selector: 'app-demo',
providers: [LocalService]
})
export class DemoComponent { }
// 4. Standalone component level
@Component({
selector: 'app-demo',
standalone: true,
providers: [LocalService] // Instance baru setiap kali
})
export class DemoComponent { }
7. Routing dan Navigasi
Angular Router memungkinkan kita membangun Single Page Application (SPA) dengan navigasi antar halaman tanpa reload browser. Router mendukung lazy loading, route guards, nested routes, dan banyak fitur lainnya.
RxJS (Reactive Extensions for JavaScript) adalah library untuk reactive programming menggunakan Observables. Angular terintegrasi erat dengan RxJS untuk menangani operasi asynchronous seperti HTTP requests, event handling, dan state management.
Konsep Dasar RxJS
Konsep
Penjelasan
Analogi
Observable
Stream data yang bisa dipublish seiring waktu
Kanal YouTube yang mengupload video berkala
Observer
Yang menerima data dari Observable
Subscriber YouTube yang menonton video
Subscription
Langganan aktif ke Observable
Tombol Subscribe yang ditekan
Operator
Fungsi untuk memanipulasi stream
Filter, edit, atau gabungkan video
Subject
Observable dan Observer sekaligus (multicasting)
Forum diskusi (bisa bicara dan mendengar)
Observable dan Operators
typescript
import { Observable, of, from, interval, Subject, BehaviorSubject } from 'rxjs';
import {
map, filter, switchMap, mergeMap, debounceTime,
distinctUntilChanged, takeUntil, catchError,
tap, retry, delay, combineLatest
} from 'rxjs/operators';
// === 1. Membuat Observable ===
const numbers$ = new Observable<number>(subscriber => {
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
subscriber.complete();
});
// Subscribe ke Observable
numbers$.subscribe({
next: value => console.log('Nilai:', value),
error: err => console.error('Error:', err),
complete: () => console.log('Selesai')
});
// === 2. Observable dari array / promise ===
const fruits$ = of('Apel', 'Mangga', 'Jeruk');
const numberArray$ = from([10, 20, 30, 40, 50]);
const timer$ = interval(1000); // Setiap 1 detik
// === 3. Operators: map, filter ===
const processed$ = numberArray$.pipe(
map(x => x * 2), // Kalikan 2
filter(x => x > 40), // Ambil yang > 40
tap(x => console.log('Processed:', x)) // Side effect
);
// Output: 60, 80, 100
// === 4. debounceTime untuk search ===
const searchInput$ = new Subject<string>();
searchInput$.pipe(
debounceTime(300), // Tunggu 300ms setelah ketikan
distinctUntilChanged(), // Hanya jika nilai berubah
filter(query => query.length >= 3), // Min 3 karakter
switchMap(query => this.searchService.search(query)) // Cancel prev
).subscribe(results => {
this.searchResults = results;
});
// Trigger search dari template:
// onSearch(event: Event) {
// this.searchInput$.next((event.target as HTMLInputElement).value);
// }
// === 5. combineLatest untuk data gabungan ===
const user$ = this.userService.getCurrentUser();
const settings$ = this.settingsService.getSettings();
combineLatest([user$, settings$]).pipe(
map(([user, settings]) => ({
...user,
theme: settings.theme,
language: settings.language
}))
).subscribe(combinedData => {
this.appState = combinedData;
});
// === 6. Subject dan BehaviorSubject ===
// Subject — tidak punya nilai awal
const clickSubject$ = new Subject<string>();
clickSubject$.subscribe(val => console.log('Click:', val));
clickSubject$.next('button-1');
// BehaviorSubject — punya nilai awal
const authState$ = new BehaviorSubject<boolean>(false);
authState$.subscribe(state => console.log('Auth:', state));
// Output: Auth: false (nilai awal)
authState$.next(true);
// Output: Auth: true
Selalu pastikan untuk unsubscribe dari Observable saat component di-destroy untuk menghindari memory leaks. Gunakan takeUntil pattern, async pipe di template, atau DestroyRef (Angular 16+).
9. HTTP Client dan API Communication
Angular menyediakan HttpClientModule yang terintegrasi dengan RxJS untuk melakukan HTTP requests ke backend API. Fitur ini mendukung interceptors, error handling, dan berbagai metode HTTP.
Mengkonfigurasi HttpClient
typescript
// app.config.ts — konfigurasi standalone
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { routes } from './app.routes';
import { authInterceptor } from './interceptors/auth.interceptor';
import { errorInterceptor } from './interceptors/error.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(
withInterceptors([authInterceptor, errorInterceptor])
)
]
};
HTTP Interceptors
typescript
// interceptors/auth.interceptor.ts
import { HttpInterceptorFn } from '@angular/common/http';
import { inject } from '@angular/core';
import { AuthService } from '../services/auth.service';
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const authService = inject(AuthService);
const token = authService.getToken();
if (token) {
const cloned = req.clone({
setHeaders: {
Authorization: 'Bearer ' + token
}
});
return next(cloned);
}
return next(req);
};
// interceptors/error.interceptor.ts
import { HttpInterceptorFn, HttpErrorResponse } from '@angular/common/http';
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { catchError, throwError } from 'rxjs';
export const errorInterceptor: HttpInterceptorFn = (req, next) => {
const router = inject(Router);
return next(req).pipe(
catchError((error: HttpErrorResponse) => {
switch (error.status) {
case 401:
router.navigate(['/login']);
break;
case 403:
alert('Anda tidak memiliki akses');
break;
case 404:
console.error('Resource tidak ditemukan');
break;
case 500:
alert('Terjadi kesalahan server');
break;
}
return throwError(() => error);
})
);
};
10. Form Handling di Angular
Angular menyediakan dua pendekatan untuk menangani forms: Template-Driven Forms dan Reactive Forms. Reactive Forms lebih disarankan untuk form kompleks karena memberikan kontrol lebih besar dan testability yang lebih baik.
Berikut adalah beberapa best practices yang harus diikuti saat mengembangkan aplikasi Angular untuk menghasilkan kode yang bersih, scalable, dan mudah di-maintain.
Daftar Best Practices
Praktik
Penjelasan
Gunakan Standalone Components
Angular 15+ mendukung standalone — lebih ringan tanpa NgModule boilerplate
Lazy Loading Routes
Gunakan loadComponent() untuk memuat halaman hanya saat dibutuhkan
OnPush Change Detection
Gunakan ChangeDetectionStrategy.OnPush untuk performa lebih baik
Avoid Logic di Template
Simpan logika di component class, bukan di template HTML
Unsubscribe Properly
Gunakan takeUntil, async pipe, atau DestroyRef
Folder Structure Rapi
Group berdasarkan fitur, bukan berdasarkan tipe file
Environment Variables
Gunakan environment.ts untuk konfigurasi berbeda (dev, staging, prod)
Unit Testing
Test setiap component dan service menggunakan Jasmine/Karma atau Jest
Angular 16+ memperkenalkan Signals sebagai alternatif dari RxJS untuk state management sederhana. Signals menyediakan reactive state dengan API yang lebih intuitif: signal(), computed(), dan effect(). Ini membantu mengurangi boilerplate dan mempercepat development.
12. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Angular:
Pertanyaan 1: Apa bahasa pemrograman utama yang digunakan oleh Angular?
a) JavaScript
b) TypeScript
c) Dart
d) CoffeeScript
Pertanyaan 2: Apa fungsi dari Dependency Injection di Angular?
a) Untuk meng-upload file ke server
b) Untuk mengelola CSS styling
c) Untuk menyediakan instance services ke komponen yang membutuhkan
d) Untuk membuat animasi
Pertanyaan 3: Operator RxJS apa yang digunakan untuk membatalkan HTTP request sebelumnya saat ada request baru?
a) mergeMap
b) concatMap
c) switchMap
d) exhaustMap
Pertanyaan 4: Apa perbedaan utama antara Template-Driven Forms dan Reactive Forms?
a) Tidak ada perbedaan
b) Reactive Forms didefinisikan di component class dengan kontrol lebih besar, Template-Driven didefinisikan di template
c) Template-Driven lebih cepat performanya
d) Reactive Forms tidak bisa digunakan dengan validasi
Pertanyaan 5: Apa fungsi dari router-outlet di Angular?
a) Menampilkan loading indicator
b) Menjadi tempat di-render-nya component berdasarkan route aktif