Angular Router: Alt Rota Tanımlaması
Angular uygulamaları, tek sayfalık uygulama (Single Page Application – SPA) mimarisinin gücünü kullanarak modern ve dinamik kullanıcı deneyimleri sunar. Bu deneyimlerin temelini, kullanıcıların farklı görünümler arasında sorunsuz bir şekilde gezinmesini sağlayan yönlendirme (routing) mekanizması oluşturur. Angular Router, bu yönlendirme ihtiyaçlarını karşılamak için güçlü ve esnek bir çözüm sunar. Uygulama karmaşıklığı arttıkça, sadece ana rotalar değil, aynı zamanda belirli bir ana rota altında hiyerarşik olarak konumlandırılmış “alt rotalar” veya “çocuk rotalar” (child routes) tanımlama ihtiyacı ortaya çıkar. Bu makale, Angular Router’da alt rotaların nasıl tanımlandığını, neden önemli olduklarını, kullanım senaryolarını ve gelişmiş özelliklerini detaylı bir şekilde ele alacaktır.
Angular Rota Temelleri
Alt rotaların derinliklerine dalmadan önce, Angular’da temel rota kavramlarını hatırlamak faydalı olacaktır. Angular Router, bir URL’yi bir bileşenle eşleştirmek için kullanılır. Bu sayede, kullanıcılar tarayıcılarının adres çubuğundaki URL’yi değiştirerek veya uygulama içindeki bağlantılara tıklayarak farklı görünümler arasında geçiş yapabilirler.
Bir Angular uygulamasında yönlendirme genellikle AppRoutingModule adında ayrı bir modülde yapılandırılır. Bu modül, uygulamanın kök modülü olan AppModule tarafından içe aktarılır. Temel rota yapılandırması şu şekildedir:
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { ContactComponent } from './contact/contact.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'contact', component: ContactComponent },
{ path: '', redirectTo: '' } // Tanımsız yollar için ana sayfaya yönlendirme
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Bu yapılandırmada:
* Routes dizisi, uygulama genelindeki tüm rotaları tanımlayan Route nesneleri içerir.
* Her Route nesnesi, bir path (URL yolu) ve bu yolla ilişkilendirilecek bir component (bileşen) tanımlar.
* RouterModule.forRoot(routes), kök yönlendirme modülünü yapılandırır ve tarayıcı geçmişi API’sini kullanarak URL’yi dinlemeye başlar.
* router-outlet etiketi, eşleşen bileşenin görüntüleneceği yer tutucudur. Genellikle app.component.html içinde bulunur: .
* routerLink direktifi, HTML bağlantılarını () Angular rotalarına bağlamak için kullanılır: Hakkımızda.
Bu temel yapı, basit uygulamalar için yeterli olsa da, daha karmaşık kullanıcı arayüzleri ve iş mantıkları için yetersiz kalmaktadır. İşte bu noktada alt rotaların gücü devreye girer.
Alt Rotalar Neden Gereklidir?
Modern web uygulamaları genellikle derinlemesine ve katmanlı bir yapıya sahiptir. Örneğin, bir yönetici paneli uygulamasını düşünün. Bu panelin “Kullanıcılar”, “Ürünler”, “Ayarlar” gibi ana bölümleri olabilir. Her bir ana bölümün de kendi içinde “Kullanıcı Listesi”, “Yeni Kullanıcı Ekle”, “Kullanıcı Detayları” veya “Genel Ayarlar”, “Güvenlik Ayarları” gibi alt bölümleri bulunabilir. Bu tür hiyerarşik yapıları düz rotalarla yönetmek karmaşıklığı artırır ve kodun okunabilirliğini azaltır.
Alt rotaların temel faydaları şunlardır:
* Modülerlik ve Kod Düzeni: Uygulamanın farklı bölümlerini mantıksal olarak izole etmeyi sağlar. Her bir ana bölümün kendi yönlendirme mantığına ve alt bileşenlerine sahip olması, kod tabanını daha düzenli ve yönetilebilir hale getirir.
* Daha İyi Kullanıcı Deneyimi (UX): Kullanıcıların bir bölüm içinde gezinirken, ana navigasyonun değişmeden kalmasını sağlar. Örneğin, bir profil sayfasında “Profil Bilgileri” ve “Şifre Değiştir” sekmeleri arasında geçiş yaparken, ana menü sabit kalır.
* Hiyerarşik URL Yapısı: URL’lerin uygulamanın hiyerarşik yapısını yansıtmasına olanak tanır (örn: /dashboard/users/123/edit). Bu, kullanıcılar ve arama motorları için daha anlamlı ve tahmin edilebilir URL’ler oluşturur.
* Tembel Yükleme (Lazy Loading): Büyük uygulamalarda, belirli bir ana rotanın ve onun tüm alt rotalarının yalnızca kullanıcı o ana rotaya gittiğinde yüklenmesini sağlayarak başlangıç yükleme süresini optimize eder. Bu, özellikle alt rotaları olan büyük özellik modülleri için kritik öneme sahiptir.
* Bileşen Kapsamının Korunması: Bir ana bileşenin kendi içinde alt bileşenleri yönetmesini ve bunların yaşam döngüsünü kontrol etmesini kolaylaştırır. Ana bileşen, alt bileşenler için bir konteyner görevi görür.
Alt Rota Tanımlaması: Adım Adım
Angular’da alt rota tanımlamak için, ana rota tanımına children özelliğini ekleriz. Bu özellik, ana rotanın altındaki rotaları içeren bir Routes dizisi alır.
Temel Yapı
Bir ana rota altında alt rotaları tanımlamak için, ana rotanın Route nesnesine bir children özelliği eklenir. Bu children dizisi, ana rotanın altındaki rotaları içeren Route nesnelerinden oluşur.
const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent, // Ana bileşen
children: [ // Alt rotalar
{ path: 'overview', component: DashboardOverviewComponent },
{ path: 'reports', component: DashboardReportsComponent },
{ path: 'settings', component: DashboardSettingsComponent }
]
},
// ... diğer rotalar
];
Bu örnekte, /dashboard yolu DashboardComponent‘i yükler. /dashboard/overview yolu ise DashboardComponent‘in içinde DashboardOverviewComponent‘i yükler. /dashboard/reports ve /dashboard/settings için de benzer durum geçerlidir.
Önemli Not: Alt rotaların yüklenebilmesi için, ana bileşen (DashboardComponent bu örnekte) kendi şablonunda bir etiketine sahip olmalıdır. Bu router-outlet, alt rotanın eşleşen bileşeninin görüntüleneceği yerdir.
Kod Örneği ve Açıklaması
Şimdi bu konsepti daha somut bir örnekle ele alalım. Bir kullanıcı profil sayfası düşünelim. Bu sayfanın “Genel Bilgiler”, “Sipariş Geçmişi” ve “Adresler” gibi alt bölümleri olsun.
Öncelikle gerekli bileşenleri oluşturalım:
ng generate component user-profile
ng generate component user-profile/general-info
ng generate component user-profile/order-history
ng generate component user-profile/addresses
Şimdi app-routing.module.ts dosyamızı güncelleyelim:
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { UserProfileComponent } from './user-profile/user-profile.component';
import { GeneralInfoComponent } from './user-profile/general-info/general-info.component';
import { OrderHistoryComponent } from './user-profile/order-history/order-history.component';
import { AddressesComponent } from './user-profile/addresses/addresses.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'profile',
component: UserProfileComponent,
children: [
{ path: 'general', component: GeneralInfoComponent },
{ path: 'orders', component: OrderHistoryComponent },
{ path: 'addresses', component: AddressesComponent }
]
},
{ path: '', redirectTo: '' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Şimdi UserProfileComponent‘in şablonunu (user-profile.component.html) düzenleyelim:
Kullanıcı Profilim
routerLink direktiflerinde göreceli yollar kullandığımıza dikkat edin (general, orders, addresses). Bu, profile rotasının altında oldukları için Angular Router’ın otomatik olarak /profile/general, /profile/orders gibi tam yolları oluşturmasını sağlar.
Boş Yol (Empty Path) ve Varsayılan Alt Rota
Bir ana rotaya gidildiğinde (örn: /profile), varsayılan olarak belirli bir alt rotanın yüklenmesini isteyebiliriz (örn: /profile/general). Bunu sağlamak için, children dizisinde boş bir path ile bir redirectTo kuralı kullanırız.
// app-routing.module.ts (UserProfileComponent'in children rotaları)
children: [
{ path: '', redirectTo: 'general', pathMatch: 'full' }, // Varsayılan alt rota
{ path: 'general', component: GeneralInfoComponent },
{ path: 'orders', component: OrderHistoryComponent },
{ path: 'addresses', component: AddressesComponent }
]
Bu yapılandırma ile, kullanıcı /profile adresine gittiğinde, Angular Router otomatik olarak /profile/general adresine yönlendirecek ve GeneralInfoComponent‘i yükleyecektir. pathMatch: 'full' özelliği, boş yolun sadece tam olarak eşleştiğinde (yani başka bir şey olmadığında) yönlendirmeyi tetiklemesini sağlar.
Parametreli Alt Rotalar
Çoğu zaman, alt rotaların belirli bir kaynağın detaylarını göstermesi gerekir. Örneğin, bir kullanıcının sipariş geçmişini görüntülerken, belirli bir siparişin detaylarını görmek için /profile/orders/123 gibi bir URL yapısı kullanmak isteyebiliriz. Burada 123, sipariş ID’sidir.
Parametreli rotalar, path içinde iki nokta üst üste (:) ile belirtilir:
children: [
// ... diğer alt rotalar
{ path: 'orders', component: OrderHistoryComponent },
{ path: 'orders/:orderId', component: OrderDetailComponent } // Parametreli alt rota
]
Bu durumda, /profile/orders/123 adresine gidildiğinde OrderDetailComponent yüklenecektir. OrderDetailComponent içinde ActivatedRoute servisini kullanarak bu parametreye erişebiliriz:
// order-detail.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-order-detail',
template:
Sipariş Detayı: {{ orderId }}
})
export class OrderDetailComponent implements OnInit {
orderId: string | null = null;
constructor(private route: ActivatedRoute) { }
ngOnInit():
this.route.paramMap.subscribe(params => {
this.orderId = params.get('orderId');
});
// Veya snapshot kullanarak (sadece bir kez okunacaksa)
// this.orderId = this.route.snapshot.paramMap.get('orderId');
}
}
paramMap bir Observable döndürdüğü için, rota parametreleri değiştiğinde (örneğin, aynı bileşende /orders/123‘ten /orders/456‘ya geçiş yapıldığında) bileşen güncellenebilir. snapshot ise parametreleri sadece bileşen ilk yüklendiğinde okur.
Ana rotadan alt rotalara parametre geçirme de mümkündür. Örneğin, /users/:userId/profile gibi bir yapıda, profile alt rotası userId parametresine erişebilir. Bu durumda, alt bileşen ActivatedRoute üzerinden hem kendi parametrelerine hem de üst rotanın parametrelerine erişebilir.
// user-profile.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-user-profile',
template:
Kullanıcı Profili: {{ userId }}
})
export class UserProfileComponent implements OnInit {
userId: string | null = null;
constructor(private route: ActivatedRoute) { }
ngOnInit(): void {
this.route.paramMap.subscribe(params => {
this.userId = params.get('userId'); // Ana rotanın parametresine erişim
});
}
}
Bu senaryoda, app-routing.module.ts‘deki ana rota tanımı şöyle olabilir:
{
path: 'users/:userId', // Ana rota parametresi
component: UserProfileComponent,
children: [
{ path: 'profile-info', component: UserProfileInfoComponent },
// ... diğer alt rotalar
]
}
UserProfileInfoComponent içinde de ActivatedRoute kullanarak userId parametresine erişilebilir. Angular Router, üst rotaların parametrelerini alt rotalara otomatik olarak miras bırakır.
Modüler Yapı ve Lazy Loading ile Alt Rotalar
Büyük Angular uygulamalarında, tüm uygulamanın tek bir modülde ve tek bir paket olarak yüklenmesi performansı olumsuz etkileyebilir. Bu sorunu çözmek için Angular, “özellik modülleri” (feature modules) ve “tembel yükleme” (lazy loading) kavramlarını sunar. Alt rotalar, bu mekanizmalarla birlikte kullanıldığında uygulamanın ölçeklenebilirliğini ve performansını önemli ölçüde artırır.
Feature Modülleri ve Alt Rotalar
Bir özellik modülü, belirli bir uygulama alanına (örn: Yönetici Paneli, Ürünler, Kullanıcılar) ait bileşenleri, servisleri ve rotaları bir araya getiren bir NgModule‘dür. Her özellik modülü kendi yönlendirme modülüne (FeatureRoutingModule) sahip olabilir. Bu modül, RouterModule.forChild(routes) kullanarak kendi rotalarını tanımlar.
Örnek olarak bir AdminModule ve onun altındaki rotaları ele alalım:
ng generate module admin --routing
Bu komut, AdminModule ve AdminRoutingModule‘i oluşturur.
// admin-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AdminDashboardComponent } from './admin-dashboard/admin-dashboard.component';
import { ManageUsersComponent } from './manage-users/manage-users.component';
import { ManageProductsComponent } from './manage-products/manage-products.component';
const routes: Routes = [
{
path: '', // Admin modülünün kök yolu
component: AdminDashboardComponent,
children: [
{ path: 'users', component: ManageUsersComponent },
{ path: 'products', component: ManageProductsComponent },
{ path: '', redirectTo: 'users', pathMatch: 'full' } // Admin modülünün varsayılan alt rotası
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)], // forChild kullanıyoruz
exports: [RouterModule]
})
export class AdminRoutingModule { }
Bu AdminRoutingModule, AdminModule içinde içe aktarılır. Ana AppRoutingModule ise bu AdminModule‘ü tembel yükleme (lazy loading) ile yükler.
Lazy Loading (Tembel Yükleme) ile Alt Rotalar
Tembel yükleme, bir modülün ve onunla ilişkili tüm bileşenlerin ve rotaların, yalnızca kullanıcı o modülün rotasına gittiğinde yüklenmesini sağlar. Bu, uygulamanın başlangıç yükleme süresini önemli ölçüde azaltır. Alt rotalarla birlikte kullanıldığında, belirli bir ana bölümün tüm alt rotaları, yalnızca ana bölümün rotasına gidildiğinde yüklenir.
AppRoutingModule içinde loadChildren özelliğini kullanarak bir modülü tembel yükleyebiliriz:
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
},
{ path: '', redirectTo: '' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Bu yapılandırma ile:
1. Kullanıcı /admin adresine gittiğinde, admin.module.ts dosyası ve içindeki tüm bileşenler, servisler ve AdminRoutingModule (kendi alt rotalarıyla birlikte) dinamik olarak yüklenir.
2. AdminRoutingModule içinde tanımlanan alt rotalar (örn: users, products), /admin/users veya /admin/products gibi URL’ler aracılığıyla erişilebilir hale gelir.
3. AdminModule yüklenene kadar, bu modülün kodu uygulama paketine dahil edilmez, bu da ilk yükleme boyutunu küçültür.
Bu yaklaşım, büyük ve karmaşık uygulamaların performansını ve yönetilebilirliğini artırmak için endüstri standardı bir yöntemdir.
Alt Rotalarda Router Outlet İsimlendirmesi (Named Outlets)
Çoğu durumda, uygulamanın ana şablonunda veya bir ana bileşenin şablonunda tek bir yeterlidir. Ancak, bazen aynı anda birden fazla bağımsız rota görünümünü görüntülemek gerekebilir. Örneğin, ana içeriğin yanında bir sohbet penceresi veya bir bildirim pop-up’ı gibi “yardımcı rotalar” (auxiliary routes) göstermek isteyebilirsiniz. Bu tür senaryolar için “isimli çıkışlar” (named outlets) kullanılır.
Bir etiketine name özelliği ekleyerek ona bir isim verebiliriz:
Daha sonra, rota yapılandırmasında outlet özelliğini kullanarak belirli bir rotayı bu isimli çıkışa yönlendirebiliriz:
const routes: Routes = [
// ... diğer rotalar
{ path: 'messages', component: MessagesComponent, outlet: 'popup' }
];
Bu rota, ana router-outlet‘i etkilemeden /messages yolunu popup isimli router-outlet‘e yükler. Bir isimli çıkışa gitmek için routerLink kullanırken, { outlets: { popup: 'messages' } } gibi bir sözdizimi kullanılır. URL’de ise bu (/popup:messages) şeklinde görünür.
İsimli çıkışlar, alt rotalarla doğrudan ilgili olmasa da, bir bileşenin içinde birden fazla bağımsız alt görünümü yönetme ihtiyacını karşıladığı için alt rota kavramının bir uzantısı olarak düşünülebilir. Özellikle, bir ana rotanın içeriği değişmeden bir alt pencerenin veya yan panelin dinamik olarak yüklenmesi gerektiğinde faydalıdır.
Yaygın Hatalar ve İpuçları
Alt rotalarla çalışırken karşılaşılabilecek bazı yaygın sorunlar ve bunlara yönelik ipuçları:
* Ana Bileşende router-outlet Unutulması: Alt rotaların bileşenleri, ana bileşenin şablonundaki router-outlet içinde görüntülenir. Eğer ana bileşende bu etiket yoksa, alt rota bileşenleri ekranda görünmez.
* Yanlış Göreceli Yollar: routerLink kullanırken veya redirectTo tanımlarken göreceli yolları (./ veya doğrudan alt yol adı) doğru kullanmak önemlidir. Bazen mutlak yollar (/) kullanılması gerektiği durumlarda göreceli yollar hata verebilir.
* pathMatch Karmaşası: pathMatch: 'full' ve pathMatch: 'prefix' arasındaki farkı anlamak önemlidir. Varsayılan değer prefix‘tir, yani URL’nin sadece başlangıcının eşleşmesi yeterlidir. full ise tüm URL’nin tam olarak eşleşmesini gerektirir. Özellikle boş yollar (path: '') veya redirectTo kuralları için pathMatch: 'full' genellikle gereklidir.
* redirectTo Döngüleri: Yanlış redirectTo tanımlamaları sonsuz yönlendirme döngülerine yol açabilir. Örneğin, bir rotanın kendini veya kendisini içeren bir rotayı yönlendirmesi.
* ActivatedRoute Snapshot vs. Observable: Rota parametrelerine erişirken, route.snapshot.paramMap.get() yalnızca bileşen ilk yüklendiğinde parametreleri alır. Eğer aynı bileşen içinde rota parametreleri değişirse (örn: /users/1‘den /users/2‘ye geçiş), bileşenin güncellenmesi için route.paramMap.subscribe() kullanarak bir gözlemlenebilir nesneye abone olmak gerekir.
* Modül İçe Aktarma Hataları: Tembel yükleme yaparken, loadChildren içinde doğru modül yolunu ve modül sınıf adını belirtmek çok önemlidir (.then(m => m.AdminModule) kısmında).
Sonuç
Angular Router’da alt rotaların tanımlanması, karmaşık ve büyük ölçekli uygulamalar geliştirmek için vazgeçilmez bir araçtır. Uygulamanın hiyerarşik yapısını URL’lere yansıtarak hem geliştiriciler için kodun okunabilirliğini ve yönetilebilirliğini artırır hem de kullanıcılar için daha sezgisel ve tutarlı bir navigasyon deneyimi sunar.
Modüler yapılandırma, parametre geçişi ve özellikle tembel yükleme ile birleştiğinde, alt rotalar Angular uygulamalarının performansını ve ölçeklenebilirliğini önemli ölçüde iyileştirir. Doğru alt rota stratejileri benimsemek, Angular projenizin uzun vadede sürdürülebilirliğini ve başarısını garantileyecektir. Bu makalede ele alınan kavramları ve örnekleri kullanarak, siz de Angular uygulamalarınızda güçlü ve esnek yönlendirme yapıları oluşturabilirsiniz.