Bu yazıda Angular ile basitçe dashboard (yönetim paneli) altyapısı hazırlayacağız. Route kullanımı, children route tanımlama, layout component kullanımı ve auth guard oluşturmayı ve kullanmayı öğreneceğiz.


Projemizi açtığımızda eğer giriş yapıldıysa dashboard ekranı açılacak, giriş yapılmadıysa login ekranı açılacak. Burada layout yapısını kullanacağız. Hemen başlayalım;


Yazının bitiminde projenin bitmiş halinin github linkini paylaşacağım.


İlk olarak projemizi oluşturalım

ng new dashboardExample

Would you like to add Angular routing? (y/N) - Yani routing'i eklemek ister misin? Cevabımız: y

Which stylesheet format would you like to use? (Use arrow keys) - Hangi stil şablonunu kullanmak istersin? Cevabımız: SCSS

cd dashboardExample
ng serve


Projemizi başlattık ve neredeyse yarısı bitmiş oldu;


Şimdi şu app.component.html'in içindekileri silelim ve içine sadece şu satırı ekleyelim;

<router-outlet></router-outlet>


Kullanacağımız componentleri tanıyalım;

  • AccountComponent = Login ve Register componentlerimizin layout'u olarak kullanacağız.
  • LoginComponent = Giriş ekranımız olacak
  • RegisterComponent = Kayıt ekranımız olacak
  • DashboardComponent = Giriş yapıldıktan sonra açılacak olan panelimizin layout'u olacak. İçerisinde SidebarComponent, HeaderComponent gibi componentleri çağıracağız ve bir içerik bölümü bırakacağız. O içerik bölümüde yönetim panelimizde kullanacağımız ekranların görüneceği kısım olacak. Böylelikle yönetim panelinde kullanacağımız her componentte header ve sidebar componentleri çağırmak zorunda kalmayacağız.
  • StartComponent = Yönetim panelimiz ilk açıldığında gelecek olan başlangıç ekranı.
  • UsersComponent = Kullanıcılar komponenti
  • SettingsComponent = Ayarlar komponenti
  • HeaderComponent = Dashboard üst bölümü.
  • SidebarComponent = Dashboard sol bölümü
  • NotFoundComponent = Olmayan bir link açıldığında çalışacak olan 404 not found ekranı


Şimdi tüm componentlerimizi sırayla oluşturalım;

ng g c components/account
ng g c components/account/login
ng g c components/account/register
ng g c components/dashboard
ng g c components/dashboard/start
ng g c components/dashboard/users
ng g c components/dashboard/settings
ng g c components/shared/header
ng g c components/shared/sidebar
ng g c components/not-found


Şimdi app-routing.module.ts dosyamızı açalım ve rotalarımızı tanımlayalım;

const routes: Routes = [
  {
    path: '',
    component: AccountComponent,
    children: [
      { path: '', component: LoginComponent },
      { path: 'register', component: RegisterComponent }
    ]
  },
  {
    path: 'dashboard',
    component: DashboardComponent,
    children: [
      { path: '', component: StartComponent },
      { path: 'users', component: UsersComponent },
      { path: 'settings', component: SettingsComponent },
    ]
  },
  { path: '**', component: NotFoundComponent }
];


Bu routing tanımlamamıza göre AccountComponent ve DashboardComponent layout görevi görecek.

Peki bu ne demek?

Çok basit bir mantığı var. Örneğimizden yola çıkacak olursak yönetim panelinde başlangıç (StartComponent), kullanıcılar (UsersComponent) ve ayarlar (SettingsComponent) sayfaları var. Bu sayfaların hepsinin üst (HeaderComponent) ve sol (SidebarComponent) bölümler aynı. Yani biz start, users ve settings componentlerinin hepsinde <app-header> ve <app-sidebar> ı çağırmamız gerekecek.

Oldu ki bir değişiklik yapmamız gerekti: Tüm bu componentlere tek tek girip değiştirmemiz gerekecek. 3 tane componentte belki bunun kontrolü kolay olur ama 20-30 veya daha üstü component sayısında bu bildiğin amelelikten başka bir şey değil. Böyle bir durumla karşılaşmak istemediğimiz için DashboardComponent adında bir component oluşturuyoruz ve biz header ve sidebar ı bu component içinde çağıracağız. Daha sonra içeriğin geleceği bölüme tıpkı AppComponent'te yaptığımız gibi <router-outlet></router-outlet> etiketlerimizi koyacağız. Böylelikle SettingsComponent'in içerisine sadece kendisiyle alakalı kodlarımızı yazacağız ve bu component çağırıldığında parent componenti yani DashboardComponentin içerisinde çağırılmış olacak.


Uzun uzun anlattık burayı umarım anlaşılmıştır.


Bu layout muhabbetini children muhabbetini birde örnek üzerinde deneyelim. Şuan projemiz şu şekilde görünüyor


AccountComponent'i 2 sütuna ayıralım. Sol taraf hem login hem register ekranlarında aynı olsun. Sağ tarafta ise child componentin içeriği görünsün.


account.component.html;

<div class="account-container">
  <div class="account-left">
    account works!
  </div>
  <div class="account-right">
    <router-outlet></router-outlet> <!-- Child component burada görünecek -->
  </div>
</div>


account.component.scss;

.account-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 100vh;
  .account-left,
  .account-right {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
  }
  .account-left {
    background-color: #ececec;
  }
}


styles.scss;

body {
  margin: 0;
}


Bu değişikliklerden sonra localhost:4200 ve localhost:4200/register ekranlarımız şu şekilde;


Login componentimizin içinde sadece <p>login works!</p> yazıyor. Register componentimizin içinde sadece <p>register works!</p> yazıyor. Ama biz bu componentlerimizin içeriğini parent componenti olan AccountComponentte yer alan <router-outlet></router-outlet> etiketlerinin olduğu bölümde görüyoruz.


Şimdi varsayalım ki giriş yaptık ve localhost:4200/dashboard a yönlendirildik bakalım nasıl görünüyor;


Routing dosyamızda tanımlamamıza göre dashboard açıldığında childrenında path değeri '' olan StartComponent in burada görünmesi gerekiyor. Ama görünmüyor, çünkü DashboardComponent'te <router-outlet></router-outlet> etiketlerimiz yok. Hemen ekleyelim;

dashboard.component.html;

<p>dashboard works!</p>
<router-outlet></router-outlet>


Ve çıktılarımız;


Artık child component, layout component (parent component) nedir bence tamamen anladık.


Şimdi DashboardComponent'te header ve sidebarı çağıralım. Birazda çeki düzen verelim.


dashboard.component.html;

<div class="dashboard-container">
  <div class="dashboard-left">
    <app-sidebar></app-sidebar>
  </div>
  <div class="dashboard-right">
    <app-header></app-header>
    <div class="dashboard-content">
      <router-outlet></router-outlet>
    </div>
  </div>
</div>


dashboard.component.scss;

.dashboard-container {
  display: flex;
  height: 100vh;
  .dashboard-left {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 270px;
    background-color: #b6d2f5;
  }
  .dashboard-right {
    flex: 7;
    .dashboard-content {
      display: flex;
      padding: 0 20px;
    }
  }
}


header.component.html;

<header>
  <p>header works!</p>
</header>


header.component.scss;

header {
  background-color: #cacfda;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
}


sidebar.component.html;

<p>sidebar works!</p>
<ul>
  <li><a routerLink="/dashboard">Başlangıç</a></li>
  <li><a routerLink="users">Kullanıcılar</a></li>
  <li><a routerLink="settings">Ayarlar</a></li>
</ul>


sidebar.component.scss;

ul {
  list-style: none;
  margin: 0;
  padding: 0;
  li {
    a {
      display: block;
      padding: 5px;
    }
  }
}


StartComponent, UsersComponent ve SettingsComponent içerisinde hiçbir değişiklik yapmıyorum.

Bakıyoruz neler olmuş;


Evet gayet leş bir görüntü olmasına rağmen gayet güzel bir yapı kurmuş olduk :)


Şimdi son adıma gelelim.

localhost:4200 e girildiğinde eğer giriş yapıldıysa direkt /dashboard a yönlendirsin.

localhost:4200/dashboard a girildiğinde ise eğer giriş yapılmamışsa giriş ekranına yönlendirsin.

Tabi biz bir giriş formu vs. yapmayacağız yoksa hem yazı çok uzun olacak hemde detaylarda kaybolup gitmeyelim. Sadece bu yapıyı kuracağız.


Bu kontrolleri ne ile yapıyoruz? Cevap: Guard

Kısaca Guard ile erişilmek istenen bir rotayı bazı kontrollerden geçiriyoruz. Detaylı anlatımı için Angular Route Guards canActivate nedir? Nasıl kullanılır? başlıklı yazıma bakabilirsiniz.


Aşağıdaki komut ile auth guard'ımızı oluşturalım (--skipTests=true ile spec dosyası istemediğimizi belirtiyoruz. Yani bunu yazmasanızda olur ama yazmadığınız zaman spec dosyasıda oluşturuyor.);

ng g guard services/auth --skipTests=true

Bu komutu yazdıktan sonra 3 tane seçenek gelecek: CanActivate - CanActivateChild - CanLoad

Burada CanActivate üzerine gelip space (boşluk) tuşuna basarak işaretleyin. Daha sonra entera basın.


Bir tanede servis dosyası oluşturalım buradan giriş yapılıp yapılmadığını kontrol ettireceğiz;

ng g s services/account --skipTests=true


İlk olarak servisimizde bir method oluşturalım ve bu bize giriş yapılıp yapılmadığını söylesin.

account.service.ts;

isLoggedIn() {
  return true; // giriş yapılmış ise true, giriş yapılmamış ise false döndürüyoruz
}

Tabiki siz projelerinizde bu kontrolü böyle yapmayın :) Mesela localStorage'de token diye bir değer olup olmadığına bakın eğer varsa o tokenın doğruluğunu bir api üzerinden kontrol edin. Eğer doğru bir token ise true çevirin. Doğru değilse false çevirin. Eğer token diye bir değer hiç yoksa yine false çevirin. Bu şekilde bir kontrol güvenli olacaktır.


Şimdi gidelim guard dosyamıza;

auth.guard.ts;

constructor(
  private accountService: AccountService,
  private router: Router
) {}

canActivate() {
  const isLogged = this.accountService.isLoggedIn();
  if (isLogged) {
    return true;
  }
  this.router.navigate(['/']);
  return false;
}


canActivate içerisinde AccountService içindeki isLoggedIn() methodumuza gidiyoruz orada yapılan kontrollere göre bize giriş yaptı ya da yapmadı bilgisini bir değişkene atıyoruz. Dönen değer true ise true çeviriyoruz ve erişmek istediğimiz component açılıyor. Eğer dönen değer false ise router.nativage ile login sayfasına yönlendiriyoruz.


Guardı yazdık şimdi kullanalım.


app-routing.module.ts içerisindeki path: 'dashboard' olan elemana canActivate: [AuthGuard] ı ekliyoruz. Yani;

{
  path: 'dashboard',
  component: DashboardComponent,
  canActivate: [AuthGuard],
  children: [
    { path: '', component: StartComponent },
    { path: 'users', component: UsersComponent },
    { path: 'settings', component: SettingsComponent },
  ]
}


Burada children içerisindeki componentlerede ekleyebilirdik bu guardı. Ama zaten /dashboard içerisindeki her component bu kontrolden geçsin istiyoruz o yüzden direkt parent componente eklememiz temiz görünmesi açısından daha iyi olacak.


Şimdi bunu yaptığımızda /dashboard - /dashboard/users - /dashboard/settings sayfalarına girebiliyoruz. Herhangi bir problem yok.

AccountService içerisindeki isLoggedIn() methodumuzdan false değeri döndürdüğümüzde ise bu sayfalara girdiğimizde bizi giriş sayfasına yönlendiriyor.


Ama isLoggedIn() den true döndüğünde giriş ekranına girdiğimizde bizi Dashboard'a yönlendirmiyor. Son olarak onuda yapalım ve bu yazıyı bitirelim.


account.component.ts;

constructor(
  private accountService: AccountService,
  private router: Router
) { }

ngOnInit() {
  const isLogged = this.accountService.isLoggedIn();
  if (isLogged) {
    this.router.navigate(['/dashboard']);
  }
}



Bu iş kadar basit. Github linkinide ekleyip bir Türk kahvesi yapayım kendime;

Örneğimizin bitmiş haline buradan ulaşabilirsiniz: https://github.com/MehmetSert/Angular-Dashboard-Example


Umarım faydalı olur.