Episode ini membahas routing dan navigasi Angular: dasar Angular Router, route configuration dengan child routes dan lazy loading, perlindungan rute dengan route guards dan resolver, serta pengelolaan query params, fragment, dan navigation extras.

Aplikasi nyata terdiri dari banyak halaman: beranda, daftar produk, detail, login. Angular Router mengatur perpindahan antar halaman ini — termasuk URL, state, dan perlindungan akses.
Episode 9 membahas dasar Angular Router, route configuration dengan child routes dan lazy loading, route guards dan resolver, serta query params, fragment, dan navigation extras. Routing yang baik membuat aplikasi terasa utuh dan navigasi antar fitur lancar.
Router diaktifkan lewat provideRouter di app.config.ts, lalu komponen root memuat halaman aktif lewat <router-outlet>.
import { provideRouter, Routes } from '@angular/router';
import { BerandaComponent } from './beranda/beranda.component';
export const routes: Routes = [
{ path: '', component: BerandaComponent },
{ path: 'produk', loadComponent: () =>
import('./produk/produk-list.component').then((m) => m.ProdukListComponent) },
{ path: 'detail/:id', component: DetailComponent },
{ path: '**', redirectTo: '' },
];Route '' adalah halaman default, detail/:id memakai route parameter, dan '**' adalah wildcard untuk halaman tidak dikenal. loadComponent membuat route di-lazy-load — kode komponen hanya diunduh saat rute diakses.
Navigasi dilakukan dengan RouterLink di template atau Router di class:
<a routerLink="/produk" routerLinkActive="aktif">Daftar Produk</a>
<a routerLink="/detail/42">Buka Detail</a>routerLinkActive="aktif" menambah class saat link sedang aktif. Dari class, gunakan router.navigate(['/detail', id]) atau router.navigateByUrl('/produk') untuk navigasi programatik, misalnya setelah login.
Halaman yang memiliki sub-halaman — misalnya area admin dengan dashboard, user, dan setting — disusun dengan child routes:
export const routes: Routes = [
{
path: 'admin',
loadComponent: () => import('./admin/admin-layout.component')
.then((m) => m.AdminLayoutComponent),
children: [
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{ path: 'dashboard', loadComponent: () =>
import('./admin/dashboard.component').then((m) => m.DashboardComponent) },
{ path: 'user', loadComponent: () =>
import('./admin/user.component').then((m) => m.UserComponent) },
],
},
];AdminLayoutComponent merender menu admin plus <router-outlet> untuk menampung halaman anak. Dengan loadComponent di setiap level, bundle dipecah per fitur sehingga halaman awal jauh lebih ringan.
Lazy loading memecah aplikasi menjadi chunk kecil yang diunduh sesuai kebutuhan. Hasilnya: initial load lebih cepat, halaman yang jarang diakses tidak membebani pengguna, dan pemisahan tanggung jawab per fitur menjadi lebih jelas.
Guards mengontrol siapa yang boleh mengakses rute. Bentuk modern adalah fungsi CanActivateFn dengan inject:
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';
export const authGuard: CanActivateFn = () => {
const auth = inject(AuthService);
const router = inject(Router);
if (auth.isLoggedIn()) {
return true;
}
return router.createUrlTree(['/login'], { queryParams: { kembali: router.url } });
};authGuard mengembalikan true jika pengguna login, atau URL login dengan query param kembali agar setelah login bisa dikembalikan ke halaman semula. Guard dipasang di route: { path: 'profil', component: ProfilComponent, canActivate: [authGuard] }.
Resolver mengambil data sebelum komponen dirender:
import { inject } from '@angular/core';
import { ResolveFn } from '@angular/router';
import { ProdukService } from './produk.service';
export const produkResolver: ResolveFn<Produk | undefined> = (route) => {
const service = inject(ProdukService);
return service.cari(Number(route.paramMap.get('id')));
};produkResolver dipanggil sebelum komponen DetailComponent aktif, sehingga data sudah tersedia di awal render. Ini menghindari kondisi "loading" yang berkedip untuk halaman detail.
Query params menyimpan state URL seperti pencarian dan filter:
import { inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
export class PencarianComponent {
private readonly route = inject(ActivatedRoute);
baca(): void {
this.route.queryParams.subscribe((params) => {
const q = params['q'] ?? '';
this.mulaiPencarian(q);
});
}
}Untuk mengirim query param saat navigasi, router.navigate(['/pencarian'], { queryParams: { q: 'angular' } }). Karena queryParams adalah Observable, komponen bisa bereaksi setiap kali pengguna mengubah filter.
Fragment adalah bagian URL setelah #, biasanya untuk anchor halaman. Navigasi dengan fragment: router.navigate(['/dokumentasi'], { fragment: 'instalasi' }). Navigation extras lain yang berguna: state untuk mengirim data tidak terlihat ke halaman tujuan, replaceUrl agar history tidak menumpuk, dan preserveQueryParams untuk mempertahankan query param saat berpindah halaman.
Inti yang harus dibawa pulang:
provideRouter(routes) mengaktifkan Angular Router; <router-outlet> menampilkan halaman aktif.detail/:id.loadComponent dan child routes membuat lazy loading per fitur.CanActivateFn melindungi rute dari akses ilegal.Di episode 10 selanjutnya kita akan membahas state management dan reactive patterns — mengelola state aplikasi dengan pola RxJS, memakai BehaviorSubject dan ReplaySubject sebagai state services, mengenal NgRx atau Akita, serta mengelola side effects secara terstruktur.