Route parameter adalah bagian alamat yang isinya berubah-ubah: /menu/1, /menu/2, dan /menu/3 dilayani satu rute menu/:id dan satu komponen, lalu komponennya membaca angka itu dari alamatnya. Bayangin loket pengambilan di warung Martabak Bang Jali. Loketnya cuma satu, tapi nomor di tiketmu yang menentukan martabak mana yang diserahkan. Rute menu/:id itu loketnya, angka di alamat itu nomor tiketnya, dan ?porsi=2 catatan tambahan di tiket yang sama.
🧪 Tebakan cepat: Kamu sedang di
/menu/1, halaman Martabak Manis Cokelat Keju. MenuDetail membaca id-nya sekali dingOnInitdenganthis.route.snapshot.paramMap.get('id'). Kamu klik tautan "Lihat juga: Martabak Telur Spesial" (/menu/2). Alamatnya berubah jadi/menu/2. Judul halamannya ikut berubah? Jawabannya ada di bagian "snapshot atau paramMap".
Rute dengan :id
// src/app/app.routes.ts
export const routes: Routes = [
{ path: '', redirectTo: 'menu', pathMatch: 'full' },
{ path: 'menu', component: MenuPage },
{ path: 'menu/:id', component: MenuDetail },
{ path: '**', component: TidakDitemukan },
]
<!-- template MenuPage, dengan RouterLink di imports -->
@for (m of menu; track m.id) {
<p>
<a [routerLink]="['/menu', m.id]">{{ m.nama }}</a>
<a [routerLink]="['/menu', m.id]" [queryParams]="{ porsi: 2 }">2 porsi</a>
</p>
}
| Alamat | Rute yang cocok | paramMap.get('id') |
|---|---|---|
/menu |
menu (MenuPage) |
gak ada |
/menu/2 |
menu/:id (MenuDetail) |
'2' |
/menu/2?porsi=2 |
menu/:id (MenuDetail) |
'2' |
- Titik dua di
:idmembuat segmen itu jadi parameter: apa pun yang tertulis di sana diterima, dan namanyaid. [routerLink]="['/menu', m.id]"menyusun alamat dari potongan-potongan, jadi tautan Martabak Telur Spesial menuju/menu/2.[queryParams]="{ porsi: 2 }"menambahkan?porsi=2di belakang alamatnya. Daftar rute gak perlu tahu soal query parameter.
Membaca id: ActivatedRoute
ActivatedRoute adalah service dari @angular/router yang berisi keterangan rute yang sedang menampilkan komponen ini: parameternya, query-nya, alamatnya.
import { Component, OnInit, inject } from '@angular/core'
import { ActivatedRoute, RouterLink } from '@angular/router'
import { MENU, Menu } from '../menu-data'
@Component({
selector: 'app-menu-detail',
standalone: true,
imports: [RouterLink],
template: `
<h2>{{ menu?.nama ?? 'Menu gak ketemu' }}</h2>
<p>{{ porsi }} porsi, total Rp{{ (menu?.harga ?? 0) * porsi }}</p>
<p>Lihat juga:
@for (m of lainnya; track m.id) {
<a [routerLink]="['/menu', m.id]">{{ m.nama }}</a>
}
</p>
`,
})
export class MenuDetail implements OnInit {
private route = inject(ActivatedRoute)
menu?: Menu
porsi = 1
get lainnya() {
return MENU.filter((m) => m.id !== this.menu?.id)
}
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id') // '2', teks
this.menu = MENU.find((m) => m.id === Number(id))
this.porsi = Number(this.route.snapshot.queryParamMap.get('porsi') ?? 1)
}
}
inject(ActivatedRoute)meminta service-nya, sama sepertiinject(KeranjangService)di pelajaran Services.snapshotadalah keadaan rute saat dibaca.snapshot.paramMap.get('id')memberi'2'untuk/menu/2, ataunullkalau rutenya gak punya parameter bernamaid.- Isinya selalu teks. Id di
MENUberupa angka, jadi ubah dulu denganNumber(id)sebelum dibandingkan. ngOnInitdipanggil Angular sekali, sesudah komponennya dibuat; detailnya di pelajaran Lifecycle Hooks.- Bentuk lama
this.route.paramsmemberi objek biasa:this.route.params.subscribe((p) => (this.id = p['id'])).
snapshot atau paramMap
Router memakai ulang komponen yang sama kalau yang berubah cuma parameternya. Dari /menu/1 ke /menu/2, MenuDetail gak dibuat lagi, jadi ngOnInit gak jalan lagi:
| Langkah | Alamat | Instance MenuDetail | Dibaca di ngOnInit |
Yang tampil |
|---|---|---|---|---|
| Buka dari Menu | /menu/1 |
#1 dibuat | '1' |
Martabak Manis Cokelat Keju |
| Klik "Lihat juga: Martabak Telur Spesial" | /menu/2 |
#1 dipakai ulang | gak dibaca lagi | Martabak Manis Cokelat Keju |
| Kembali ke Menu, buka lagi | /menu/2 |
#2 dibuat | '2' |
Martabak Telur Spesial |
Jadi judulnya gak berubah: alamatnya /menu/2, tapi halamannya masih Martabak Manis Cokelat Keju. Itu jawaban tebakannya. route.snapshot sendiri sudah berisi id baru; yang basi adalah salinan yang kamu ambil sekali di ngOnInit.
Kalau halamannya punya tautan ke id lain, dengarkan perubahannya dengan paramMap, sebuah Observable:
menu = signal<Menu | undefined>(undefined)
porsi = signal(1)
ngOnInit() {
this.route.paramMap.subscribe((params) => {
this.menu.set(MENU.find((m) => m.id === Number(params.get('id'))))
})
this.route.queryParamMap.subscribe((query) => {
this.porsi.set(Number(query.get('porsi') ?? 1))
})
}
Template-nya membaca menu()?.nama dan porsi(). Tiap kali parameternya berubah, fungsinya jalan lagi, signal-nya berganti, dan halamannya ikut berganti. Kenapa signal: sejak Angular 22 komponen secara bawaan OnPush, jadi properti biasa yang diganti dari dalam subscribe gak memberi kabar, dan judulnya tetap menu lama (dicoba di editor latihan, Angular 22). Langganan ke Observable milik ActivatedRoute gak perlu kamu unsubscribe sendiri: router membereskannya saat komponennya dihancurkan.
Query parameter: ?porsi=2
Path parameter (/menu/2) menunjuk barang yang mana, dan rutenya gak cocok tanpa dia. Query parameter (?porsi=2, ?urut=harga) cuma keterangan tambahan yang boleh ada boleh enggak.
- Dibaca dengan
queryParamMap.get('porsi'):'2'kalau ada,nullkalau gak ada. - Isinya juga teks.
'2' + 1hasilnya'21', jadiNumber(...)dulu. - Dari kode:
this.router.navigate(['/menu', 2], { queryParams: { porsi: 2 } })membuka/menu/2?porsi=2.
Latihan: id dari editor
Editor latihan gak punya daftar rute, jadi editor memberi rute aktif palsu dengan id 9f42c1. Komponen UserComponent di latihan cukup meminta ActivatedRoute, membaca paramMap.get('id') di ngOnInit (lewat snapshot atau subscribe), lalu menampilkannya: <p>User ID: {{ userId }}</p> jadi User ID: 9f42c1.
💡 id sebagai @Input
Di proyek Angular CLI, provideRouter(routes, withComponentInputBinding()) mengisi @Input() id milik komponen rute langsung dari alamatnya, termasuk saat parameternya berubah. Editor latihan dan Playground memasang router-nya sendiri tanpa fitur itu, jadi di sini kita memakai ActivatedRoute.
⚠️ Jebakan yang sering ketemu
- snapshot di halaman yang menautkan ke dirinya sendiri. Dari
/menu/1ke/menu/2komponennya dipakai ulang danngOnInitgak jalan lagi. PakaiparamMap.subscribe(...). - Nama parameternya beda. Rute
menu/:menuIddibaca denganget('id')memberinull, dan halamannya menulis "Menu gak ketemu". Nama di rute dan diget()harus sama persis. - Lupa id itu teks.
Number(id)sebelum dibandingkan dengan angka atau dijumlahkan. - Detail latihan. Yang dinilai: ada
<p>, kodenya memuatActivatedRoutedanparamMap, dan<p>-nya memuat9f42c1. Angka itu harus datang dari rute, bukan diketik di template.
TL;DR: Rute menu/:id melayani /menu/1, /menu/2, dan seterusnya dengan satu komponen. Komponen itu membaca parameternya lewat inject(ActivatedRoute): snapshot.paramMap.get('id') sekali di ngOnInit, atau paramMap.subscribe(...) kalau halamannya bisa pindah ke id lain, karena router memakai ulang komponen yang sama dan ngOnInit gak jalan lagi. Query parameter ?porsi=2 dikirim dengan [queryParams] dan dibaca dengan queryParamMap.get('porsi'). Semua nilai dari alamat berupa teks atau null, jadi Number(...) dulu sebelum dihitung.