Bu kılavuzda, gönderdiğiniz Complete Angular 22 - Ultimate Guide kurs içeriğini satır satır inceleyip modern yazılım geliştirme dünyasındaki karşılıklarını, teorilerini ve pratik uygulamalarını çıkaracağız.

İlk olarak, kursun vaat ettiği hedefleri içeren bölümün ne anlama geldiğini açıklayarak başlayalım.


"Öğrenecekleriniz" Bölümünün Açıklaması

Bu başlık altındaki maddeler, kurs bittiğinde kazanacağınız profesyonel yetenekleri gösterir:


BÖLÜM 1: Giriş ve Temel Yapı Tasarımı (Introduction & Basics)

Bu bölüm, kod yazmaya başlamadan önce Angular'ın arkasındaki fabrikayı anlamamızı sağlar.

1. Angular Nedir ve Amaçları Nelerdir?

Angular, Google tarafından geliştirilen büyük ve kurumsal web uygulamaları üretmeye yarayan bir framework (yazılım iskeleti) sistemidir. Amacı, kodların düzenli olmasını sağlamak, hızlı çalışan sayfalar üretmek ve ekiplerin aynı kurallarla kod yazmasını kolaylaştırmaktır. [1, 2]

2. Angular Kod Derleme Süreci (Code Compilation Process)

Tarayıcılar (Chrome, Edge vb.) Angular kodunu (TypeScript) doğrudan okuyamaz. Angular derleyicisi (Compiler), yazdığımız modern kodları tarayıcının anlayacağı saf JavaScript diline çevirir. Proje yayına alınırken bu işlem önceden yapılır (AoT - Ahead of Time Compilation), böylece web sitesi açılır açılmaz çok hızlı yüklenir.

3. Ana Yapı Taşları ve Mimari (Building Blocks & Architecture)

Angular üç ana parçadan oluşur:

4. Uygulama Klasör Yapısı (App Folder Structure)

Büyük projelerde kaybolmamak için kodlar belirli bir düzende tutulur.


BÖLÜM 2: TypeScript Temelleri (TypeScript Essentials)

TypeScript, JavaScript dilinin daha güvenli ve akıllı halidir. Hataları daha kod yazarken yakalamamızı sağlar.

1. Veri Tipleri (Data Types) ve Union Types

TypeScript'te bir değişkenin ne saklayacağını önceden söyleriz.

// Temel Tipler

let kullaniciAdi: string = "Ahmet";

let yas: number = 25;

let aktifMi: boolean = true;

 

// Union Types (Ya o, ya bu olabilir)

let telefon: string | number;

telefon = "0555...";

telefon = 555123; // İkisi de geçerlidir.

2. Diziler (Arrays) ve Tuples

Birden fazla veriyi listelemek için kullanılır. Tuple ise eleman sayısı ve tipleri sabit olan özel dizilerdir.

let alisverisListesi: string[] = ["Elma", "Armut", "Muz"];

 

// Tuple Örneği (İlk eleman string, ikinci eleman sayı olmak zorunda)

let kullanıcıKutusu: [string, number] = ["Admin", 1];

3. Nesne Kalıpları (Object Literals) ve Type Aliases

Kendi özel veri tipimizi oluşturmamızı sağlar.

// Type Alias ile şablon oluşturma

type Gorev = {

  id: number;

  baslik: string;

  tamamlandi: boolean;

};

 

// Şablonu kullanma

let yeniGorev: Gorev = {

  id: 1,

  baslik: "Angular Çalış",

  tamamlandi: false

};

4. Fonksiyonlar ve Arrow Functions

İş yapan kod bloklarıdır. Ok fonksiyonları (Arrow Functions) daha kısa yazım sunar.

// Normal Fonksiyon

function topla(a: number, b: number): number {

  return a + b;

}

 

// Arrow Fonksiyon

const carp = (x: number, y: number): number => x * y;

5. Rest Parameters, Spread Operator ve Destructuring

Verileri parçalamak veya birleştirmek için kullanılan sihirli araçlardır.

// Spread (Dağıtma/Birleştirme)

let eskiSayilar = [1, 2];

let yeniSayilar = [...eskiSayilar, 3, 4]; // [1, 2, 3, 4] olur.

 

// Destructuring (Kutudan çıkarma)

const ogrenci = { isim: "Can", not: 90 };

const { isim, not } = ogrenci; // Artık doğrudan 'isim' yazarak erişebiliriz.

6. Sınıflar (Classes), Constructors ve Access Modifiers

Nesne yönelimli programlamanın kalbidir. Sınıflar bir nesnenin fabrikası gibidir.

class Araba {

  // Access Modifiers (Erişim Belirteçleri): public veya private

  private motorGucu: number;

  public marka: string;

 

  // Constructor (Yapıcı Metot): Sınıf oluşturulurken ilk çalışan yer

  constructor(markaAdi: string, guc: number) {

    this.marka = markaAdi;

    this.motorGucu = guc;

  }

}

 

let benimArabam = new Araba("Toyota", 110);


BÖLÜM 3: İlk Angular Uygulaması ve Pratik Kodlama (First App in Angular)

1. Angular CLI Kurulumu ve Proje Oluşturma

Komut satırından Angular projesi üretmemizi sağlayan aracı bilgisayara kurarız.

# Kurulum komutu

npm install -g @angular/cli

 

# Yeni proje oluşturma

ng new ilk-projem

 

# Projeyi ayağa kaldırma ve tarayıcıda açma

cd ilk-projem

ng serve --open

2. Bileşenleri (Components) Anlamak

Bileşenler web sayfasının hücreleridir. Bir bileşen 3 ana parçadan oluşur: HTML (görüntü), CSS (stil) ve TypeScript (akıl/mantık).

// merhaba.component.ts

import { Component } from '@angular/core';

 

@Component({

  selector: 'app-merhaba',

  standalone: true,

  template: `<h1>Merhaba Dünya! Benim adım {{ isim }}</h1>`,

  styles: [`h1 { color: blue; }`]

})

export class MerhabaComponent {

  isim: string = 'Angular Geliştiricisi';

}

3. Bootstrapping Process (Açılış Süreci)

Uygulama ilk açıldığında main.ts dosyası tetiklenir. Bu dosya Angular motorunu çalıştırır ve kök bileşen olan AppComponent yapısını index.html içindeki <app-root></app-root> etiketinin içine yerleştirir.

4. Temel Yönlendirme (Basic Routing)

Sayfalar arası geçişi sağlar. Kullanıcı üst menüden "Hakkımızda" linkine tıkladığında sayfa yenilenmeden ilgili bileşen ekrana gelir.

// app.routes.ts

import { Routes } from '@angular/router';

import { AnasayfaComponent } from './anasayfa/anasayfa.component';

import { IletisimComponent } from './iletisim/iletisim.component';

 

export const routes: Routes = [

  { path: '', component: AnasayfaComponent },

  { path: 'iletisim', component: IletisimComponent }

];


BÖLÜM 4: Veri Bağlama Yöntemleri (Data Bindings)

TypeScript dosyasındaki verileri HTML ekranına aktarma ve ekrandaki hareketleri yakalama yöntemleridir.

1. Interpolation (Yazı Ekleme) ve Property Binding (Özellik Bağlama)

<!-- Interpolation -->

<p>Hoş geldin, {{ kullanici }}</p>

 

<!-- Property Binding -->

<button [disabled]="butonKilitliMi">Tıkla</button>

2. Event Binding (Olay Yakalama) ve Two-Way Binding (Çift Yönlü Bağlama)

<!-- Event Binding -->

<button (click)="girişYap()">Giriş</button>

 

<!-- Two-Way Binding -->

<input [(ngModel)]="aramaMetni" placeholder="Ara...">

<p>Aranan kelime: {{ aramaMetni }}</p>

3. Stil ve Klas Bağlama (Style & Class Binding)

Şarta bağlı olarak elementlerin renklerini veya CSS sınıflarını değiştirmemizi sağlar.

<!-- Şart doğruysa arka planı kırmızı yap -->

<div [style.background-color]="hataVarMi ? 'red' : 'green'">Mesaj</div>

 

<!-- Şart doğruysa 'aktif' CSS sınıfını yükle -->

<div [class.aktif]="sayfaSeciliMi">Kart İçeriği</div>

4. Yeni Nesil Kontrol Blokları (@if, @for, @switch)

Angular 22 ile tamamen kararlı hale gelen, HTML içinde döngü ve şart yazmayı kolaylaştıran modern yapılardır. [3, 4]

<!-- @if ve @else kullanımı -->

@if (yukleniyor) {

  <p>Veriler getiriliyor...</p>

} @else {

  <p>Veriler yüklendi!</p>

}

 

<!-- @for kullanımı (Döngü) -->

<ul>

  @for (urun of urunler; track urun.id; let i = $index) {

    <li>{{ i + 1 }} - {{ urun.ad }}</li>

  }

</ul>


BÖLÜM 5: Görev Yöneticisi Uygulaması Ödevi (Task Manager Project - Lab)

Öğrendiğimiz veri bağlama ve kontrol bloklarını pekiştirmek için bir Görev Yöneticisi tasarlayalım.

Uygulama Adımları:

  1. Bir görev listesi dizisi tanımlayacağız.
  2. @for kullanarak bu görevleri ekranda listeleyeceğiz.
  3. Ekleme butonu koyup yeni görev girişi sağlayacağız.

// task-manager.component.ts

import { Component } from '@angular/core';

import { FormsModule } from '@angular/forms';

 

@Component({

  selector: 'app-task-manager',

  standalone: true,

  imports: [FormsModule],

  template: `

    <input [(ngModel)]="yeniGorevBasligi" placeholder="Görev yaz...">

    <button (click)="gorevEkle()">Ekle</button>

 

    @for (g of gorevler; track g.id) {

      <div [style.text-decoration]="g.bitti ? 'line-through' : 'none'">

        <input type="checkbox" [(ngModel)]="g.bitti">

        {{ g.baslik }}

      </div>

    }

  `

})

export class TaskManagerComponent {

  yeniGorevBasligi = '';

  gorevler = [

    { id: 1, baslik: 'Market Alışverişi', bitti: false },

    { id: 2, baslik: 'Kod İnceleme', bitti: true }

  ];

 

  gorevEkle() {

    if(this.yeniGorevBasligi.trim()) {

      this.gorevler.push({

        id: Date.now(),

        baslik: this.yeniGorevBasligi,

        bitti: false

      });

      this.yeniGorevBasligi = '';

    }

  }

}


BÖLÜM 6: Hata Ayıklama (Debugging)

Kodlarımız çalışmadığında nerede hata yaptığımızı bulma sanatıdır.


BÖLÜM 7: Servisler ve Bağımlılık Enjeksiyonu (Services & DI)

Bileşenlerin sadece görüntüyü yönetmesi gerekir. Veri çekme, hesaplama gibi ağır işleri Servisler üstlenir.

1. Servis Oluşturma ve Tüketme

Bir servisi projenin her yerinde kullanabilmek için ortak bir işçi olarak tanımlarız.

// veri.service.ts

import { Injectable } from '@angular/core';

 

@Injectable({

  providedIn: 'root' // Tüm uygulamada tek bir kopya olarak çalışır

})

export class VeriService {

  private loglar: string[] = [];

 

  logEkle(mesaj: string) {

    this.loglar.push(mesaj);

    console.log("Yeni Log: " + mesaj);

  }

}

2. Bağımlılık Enjeksiyonu (Dependency Injection - DI)

Bileşenlerin ihtiyaç duyduğu servisleri kendi içlerinde sıfırdan üretmek yerine, Angular motorundan "bana bu servisi getir" diyerek talep etmesi yöntemidir. Angular 22 ile birlikte gelen modern inject fonksiyonu bu işi çok kolaylaştırır. [3, 5]

// ana.component.ts

import { Component, inject } from '@angular/core';

import { VeriService } from './veri.service';

 

@Component({ selector: 'app-ana', standalone: true, template: `<button (click)="islem()">Logla</button>` })

export class AnaComponent {

  // Yeni ve modern yöntem: inject kullanımı

  private veriServisi = inject(VeriService);

 

  islem() {

    this.veriServisi.logEkle("Ana sayfaya tıklandı!");

  }

}


BÖLÜM 8: Borular / Filtreler (Pipes)

Pipes, ekrandaki verileri kullanıcının gözüne hoş gelecek şekilde anlık olarak biçimlendiren dönüştürücülerdir. Verinin aslı değişmez, sadece görünüşü değişir.

1. Hazır Pipes Kullanımı

Angular içinde tarih, para birimi, büyük/küçük harf gibi dönüştürücüler hazır gelir.

<!-- Yazıyı büyük harfe çevirir: AHMET -->

<p>{{ 'ahmet' | uppercase }}</p>

 

<!-- Parayı dolar formatına sokar: $100.00 -->

<p>{{ 100 | currency }}</p>

2. Özel Pipe (Custom Pipe) Yapımı

Kendi özel filtrelerimizi de yazabiliriz. Örneğin gelen metni kısaltan bir özetleme borusu yapalım:

// ozet.pipe.ts

import { Pipe, PipeTransform } from '@angular/core';

 

@Component({ }) // Pipe tanımlaması

@Pipe({

  name: 'ozet',

  standalone: true

})

export class OzetPipe implements PipeTransform {

  transform(value: string, limit: number = 10): string {

    if (!value) return '';

    return value.length > limit ? value.substring(0, limit) + '...' : value;

  }

}

HTML içinde kullanımı:

<!-- Çıktı: Uzun bir m... -->

<p>{{ 'Uzun bir makale metni buraya gelir' | ozet:10 }}</p>


BÖLÜM 9: HTTP İletişimi ve HttpClient (HttpClient)

Uygulamamızın internetteki bir sunucuyla (REST API) konuşmasını sağlayan modüldür.

// calisan.service.ts

import { inject, Injectable } from '@angular/core';

import { HttpClient } from '@angular/common/http';

 

@Injectable({ providedIn: 'root' })

export class CalisanService {

  private http = inject(HttpClient);

  private apiAdresi = 'https://ornek.com';

 

  // Veri Getirme (GET)

  calisanlariGetir() {

    return this.http.get(this.apiAdresi);

  }

 

  // Yeni Ekleme (POST)

  calisanEkle(yeniCalisan: any) {

    return this.http.post(this.apiAdresi, yeniCalisan);

  }

 

  // Silme (DELETE)

  calisanSil(id: number) {

    return this.http.delete(`${this.apiAdresi}/${id}`);

  }

}

HTTP Interceptors (Yol Kesenler)

Uygulamadan çıkan her isteğin veya gelen her cevabın önünü kesip ortak işlemler yapmayı sağlar. Örneğin, her isteğin arkasına güvenlik token'ı (JWT) eklemek veya hataları merkezi bir yerde yakalamak için kullanılır.


BÖLÜM 10: Veri Tablosu Geliştirme Laboratuvarı (Working with Data Grid)

Gerçek dünyada en çok yapılan işlerden biri, gelen verileri sayfalı, aramalı bir tabloda göstermektir.

Gelişmiş Arama ve Sayfalama Uygulaması:
Kullanıcı arama kutusuna yazı yazdığı an sunucuya hemen istek gitmesini önlemek için belirli bir süre bekleme (Debounce) mekanizması eklenir.

// Veri tablosu mantığı örneği

import { Component, OnInit, inject } from '@angular/core';

import { HttpClient } from '@angular/common/http';

import { Subject, debounceTime, distinctUntilChanged } from 'rxjs';

 

@Component({

  selector: 'app-employee-table',

  template: `

    <input (input)="onSearch($event)" placeholder="İsim ile ara...">

    <table>

      @for(emp of filteredEmployees; track emp.id) {

        <tr><td>{{ emp.name }}</td></tr>

      }

    </table>

  `

})

export class EmployeeTableComponent implements OnInit {

  private http = inject(HttpClient);

  private searchSubject = new Subject<string>();

 

  employees: any[] = [];

  filteredEmployees: any[] = [];

 

  ngOnInit() {

    // Sunucudan ham veriyi çek

    this.http.get<any[]>('https://api.com').subscribe(data => {

      this.employees = data;

      this.filteredEmployees = data;

    });

 

    // Arama kutusuna yazarken 400 milisaniye bekle (Debounce)

    this.searchSubject.pipe(

      debounceTime(400),

      distinctUntilChanged()

    ).subscribe(searchText => {

      this.filteredEmployees = this.employees.filter(e =>

        e.name.toLowerCase().includes(searchText.toLowerCase())

      );

    });

  }

 

  onSearch(event: any) {

    this.searchSubject.next(event.target.value);

  }

}


BÖLÜM 11: Form Yönetimi (Template-Driven & Reactive Forms)

Angular'da formlar ikiye ayrılır: Basit formlar ve kontrollü/dinamik formlar.

1. Template-Driven Forms (Şablon Odaklı Formlar)

Daha çok HTML ağırlıklı, basit giriş formlarında tercih edilir. Doğrulamalar (Validation) HTML etiketleri üzerine yazılır.

<form #kullaniciFormu="ngForm" (ngSubmit)="kaydet(kullaniciFormu.value)">

  <input name="eposta" ngModel required email #emailKutusu="ngModel">

 

  @if (emailKutusu.invalid && emailKutusu.touched) {

    <small style="color: red;">Geçerli bir e-posta yazınız!</small>

  }

 

  <button [disabled]="kullaniciFormu.invalid">Gönder</button>

</form>

2. Reactive Forms (Reaktif / Dinamik Formlar)

Bütün kontrolün TypeScript kodlarında olduğu, çok daha güçlü ve test edilebilir form yapısıdır. Angular 22 ile birlikte reaktif formların veri tipleri çok daha güvenli hale gelmiştir. [3, 4]

import { Component, inject } from '@angular/core';

import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';

 

@Component({

  selector: 'app-kayit-formu',

  standalone: true,

  imports: [ReactiveFormsModule],

  template: `

    <form [formGroup]="profilFormu" (ngSubmit)="gonder()">

      <input formControlName="kullaniciAdi">

      <button [disabled]="profilFormu.invalid">Kaydet</button>

    </form>

  `

})

export class KayitFormuComponent {

  private fb = inject(FormBuilder);

 

  profilFormu = this.fb.group({

    kullaniciAdi: ['', [Validators.required, Validators.minLength(3)]]

  });

 

  gonder() {

    console.log(this.profilFormu.value);

  }

}


BÖLÜM 12: Görsel Bileşenler (Angular Material)

Google'ın hazırladığı hazır tasarım kütüphanesidir. Sıfırdan buton veya takvim tasarlamak yerine bu hazır yapıları çağırırız.


BÖLÜM 13: Bileşen Yaşam Döngüsü (Component Lifecycle Hooks)

Bir bileşen ekrana ilk çizildiği andan, ekrandan silindiği ana kadar belirli aşamalardan geçer. Bu aşamalarda kod çalıştırmamızı sağlayan özel metotlar vardır.

Metot Adı

Ne Zaman Çalışır?

En Sık Kullanım Amacı

ngOnChanges

Dışarıdan gelen bir girdi (@Input) değiştiğinde.

Girdi değişikliklerini takip etmek.

ngOnInit

Bileşen ilk kez ayağa kalkıp ekrana çizilmeye hazırlandığında.

Sunucudan ilk verileri çekmek.

ngAfterViewInit

Bileşenin HTML görüntüsü ve alt elemanları tamamen yüklendiğinde.

Doğrudan HTML elementlerine müdahale etmek.

ngOnDestroy

Kullanıcı başka sayfaya geçtiğinde ve bileşen yok edildiğinde.

Açık kalan sayaçları ve bağlantıları kapatıp hafızayı temizlemek.


BÖLÜM 14: Kimlik Doğrulama ve Güvenlik (Authentication & Security)

Uygulamanın kurumsal seviyede korunmasını sağlar.

1. JWT (JSON Web Token) Nedir?

Kullanıcı giriş yaptığında sunucu ona şifreli bir kimlik kartı metni (Token) verir. Uygulama bu kartı tarayıcıda saklar ve sunucuya her veri isteği gönderdiğinde bu kartı göstererek kimliğini kanıtlar.

2. CanActivate Guard (Sayfa Koruyucuları)

Kullanıcının giriş yapmadan gizli sayfalara (Örn: Yönetici Paneli) girmesini engelleyen yol barikatlarıdır. Eğer giriş yapılmamışsa kullanıcıyı doğrudan giriş sayfasına fırlatır.

3. Web Güvenliği (XSS ve XSRF Koruması)


BÖLÜM 15: Bileşenler Arası Gelişmiş İletişim (Component Communication)

Aynı sayfadaki farklı bileşenlerin birbiriyle konuşma yöntemleridir.

1. Parent to Child (Anne-Babadan Çocuğa) - Input Binding

Bir üst bileşenin altındaki bileşene veri göndermesidir.

// alt.component.ts

@Input() gelenMesaj: string = '';

<!-- ana.component.html -->

<app-alt [gelenMesaj]="'Seni seviyorum evlat'"></app-alt>

2. Child to Parent (Çocuktan Anne-Babaya) - Output & Custom Events

Alt bileşenin yukarıya sinyal veya olay fırlatmasıdır.

// alt.component.ts

@Output() tiklamaSinyali = new EventEmitter<void>();

 

butonaBasildi() {

  this.tiklamaSinyali.emit();

}

3. RxJS Reaktif Konuşma (BehaviorSubject)

Birbirinden tamamen bağımsız uzak bileşenlerin, ortak bir yayın kanalı üzerinden haberleşmesidir. Kanala yeni bir veri eklendiğinde, o kanalı dinleyen tüm bileşenler anında güncellenir.

 

Gerekli tüm konuları sırasıyla, adım adım çalışan, birbirine entegre ve tamamen bağımsız çalıştırabileceğiniz 15 farklı komple mini proje halinde tasarladım.

Dosyadaki tüm başlıkları, Angular 22'nin en güncel standartları olan Standalone Bileşenler, inject() fonksiyonu ve yeni kontrol blokları (@if, @for) ile hazırladım.


PROJE 1: Giriş, Mimari ve Klasör Yapısı (Introduction & App Structure)

Amaç: Angular uygulamasının ana giriş noktalarını, kök bileşeni (AppComponent) ve bootstrap sürecini simüle etmek.

// src/app/app.config.ts

import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';

 

export const appConfig: ApplicationConfig = {

  providers: [

    provideZoneChangeDetection({ eventCoalescing: true })

  ]

};

 

// src/app/app.component.ts

import { Component } from '@angular/core';

 

@Component({

  selector: 'app-root',

  standalone: true,

  template: `

    <header class="app-header">

      <h1>Kurumsal Mimari Başlangıç Projesi</h1>

    </header>

    <main class="app-content">

      <p>Angular 22 uygulaması başarıyla bootstrap edildi ve klasör yapısı doğrulandı.</p>

    </main>

  `,

  styles: [`

    .app-header { background: #1976d2; color: white; padding: 15px; text-align: center; }

    .app-content { padding: 20px; font-family: sans-serif; }

  `]

})

export class AppComponent {}

 

// src/main.ts

import { bootstrapApplication } from '@angular/platform-browser';

import { AppComponent } from './app/app.component';

import { appConfig } from './app/app.config';

 

bootstrapApplication(AppComponent, appConfig)

  .catch((err) => console.error(err));


PROJE 2: TypeScript Esasları (TypeScript Essentials)

Amaç: Güvenli veri tipleri, Type Aliases, Classes ve Access Modifiers içeren bir veri modeli simülasyonu çalıştırmak.

// src/app/typescript-demo.component.ts

import { Component, OnInit } from '@angular/core';

 

// 1. Type Alias Tanımlaması

type KullaniciTipi = 'Admin' | 'Personel' | 'Ziyaretci';

 

interface IKullanici {

  id: number;

  isim: string;

  rol: KullaniciTipi;

}

 

// 2. OOP Sınıf Yapısı

class SirketYoneticisi {

  private maasKatsayisi: number = 1.5; // Access Modifier (Private)

 

  constructor(public sirketAdı: string) {} // Otomatik Property Tanımlama

 

  public primHesapla(tabanNot: number): number {

    return tabanNot * this.maasKatsayisi;

  }

}

 

@Component({

  selector: 'app-ts-demo',

  standalone: true,

  template: `

    <div style="border: 1px solid #ccc; padding: 15px; margin: 10px;">

      <h3>TypeScript Nesne ve Sınıf Çıktıları</h3>

      <p><strong>Kullanıcı:</strong> {{ aktifKullanici.isim }} (Rol: {{ aktifKullanici.rol }})</p>

      <p><strong>Şirket:</strong> {{ sirket.sirketAdı }}</p>

      <p><strong>Yönetici Primi:</strong> {{ hesaplananPrim }} TL</p>

    </div>

  `

})

export class TypescriptDemoComponent implements OnInit {

  // Tipli değişken tanımlamaları

  aktifKullanici!: IKullanici;

  sirket = new SirketYoneticisi('Teknoloji A.Ş.');

  hesaplananPrim: number = 0;

 

  ngOnInit() {

    // Nesne oluşturma ve Destructuring

    const hamVeri = { id: 101, isim: 'Can Yılmaz', rol: 'Admin' as KullaniciTipi, sehir: 'Isparta' };

    const { id, isim, rol } = hamVeri; // Destructuring

   

    this.aktifKullanici = { id, isim, rol };

    this.hesaplananPrim = this.sirket.primHesapla(5000);

  }

}


PROJE 3: İlk Uygulama ve Temel Yönlendirme (First App & Basic Routing)

Amaç: Sayfa yenilenmeden çalışan (Single Page App) iki farklı sayfa arası geçiş mekanizması.

// src/app/pages.components.ts

import { Component } from '@angular/core';

 

@Component({

  standalone: true,

  template: `<h2>Ana Sayfaya Hoş Geldiniz</h2><p>Burası giriş ekranıdır.</p>`

})

export class HomePagesComponent {}

 

@Component({

  standalone: true,

  template: `<h2>Hakkımızda</h2><p>Kurumsal Angular 22 çözümleri üretiyoruz.</p>`

})

export class AboutPagesComponent {}

 

// src/app/app.routes.ts

import { Routes } from '@angular/router';

import { HomePagesComponent, AboutPagesComponent } from './pages.components';

 

export const routes: Routes = [

  { path: '', component: HomePagesComponent },

  { path: 'hakkimizda', component: AboutPagesComponent }

];

 

// src/app/app.component.ts (Yönlendirici Ana Bileşen)

import { Component } from '@angular/core';

import { RouterOutlet, RouterLink } from '@angular/router';

 

@Component({

  selector: 'app-root',

  standalone: true,

  imports: [RouterOutlet, RouterLink],

  template: `

    <nav style="padding: 10px; background: #eee;">

      <a routerLink="/" style="margin-right: 10px;">Ana Sayfa</a>

      <a routerLink="/hakkimizda">Hakkımızda</a>

    </nav>

    <hr>

    <router-outlet></router-outlet>

  `

})

export class AppComponent {}


PROJE 4: Veri Bağlama ve Yeni Kontrol Blokları (Data Bindings & @if/@for)

Amaç: Tek yönlü, çift yönlü veri bağlama, olay yakalama ve Angular 22 şart/döngü bloklarının kullanımı.

import { Component } from '@angular/core';

import { FormsModule } from '@angular/forms';

 

@Component({

  selector: 'app-binding-demo',

  standalone: true,

  imports: [FormsModule],

  template: `

    <div style="padding: 20px;">

      <!-- Property Binding & Interpolation -->

      <h3 [style.color]="baslikRengi">Dinamik Başlık: {{ uygulamaAdi }}</h3>

     

      <!-- Two-Way Binding -->

      <input [(ngModel)]="kullaniciGirdisi" placeholder="Bir şeyler yazın...">

      <p>Anlık Yazılan: {{ kullaniciGirdisi }}</p>

 

      <!-- Event Binding -->

      <button (click)="girdiyiTemizle()">Temizle</button>

      <hr>

 

      <!-- Yeni @if Yapısı -->

      @if (kullaniciGirdisi.length > 5) {

        <div style="color: green;">Güvenli ve uzun bir metin yazdınız!</div>

      } @else {

        <div style="color: red;">Metin çok kısa (En az 6 karakter).</div>

      }

      <hr>

 

      <!-- Yeni @for Yapısı -->

      <h4>Sistem Günlükleri</h4>

      <ul>

        @for (log of loglar; track log.id; let i = $index) {

          <li>{{ i + 1 }} - {{ log.mesaj }}</li>

        } @empty {

          <li>Henüz hiçbir işlem kaydı yok.</li>

        }

      </ul>

    </div>

  `

})

export class BindingDemoComponent {

  uygulamaAdi: string = 'Veri Kontrol Paneli';

  baslikRengi: string = '#2c3e50';

  kullaniciGirdisi: string = '';

 

  loglar = [

    { id: 1, mesaj: 'Sistem başlatıldı.' },

    { id: 2, mesaj: 'Oturum açma isteği gönderildi.' }

  ];

 

  girdiyiTemizle() {

    this.kullaniciGirdisi = '';

  }

}


PROJE 5: Görev Yöneticisi Laboratuvarı (Task Manager Lab)

Amaç: Tamamen bellek üzerinde çalışan, ekleme ve durum değiştirme özellikli görev takip kartı.

import { Component } from '@angular/core';

import { FormsModule } from '@angular/forms';

 

interface IGorev {

  id: number;

  baslik: string;

  tamamlandi: boolean;

}

 

@Component({

  selector: 'app-task-manager',

  standalone: true,

  imports: [FormsModule],

  template: `

    <div style="max-width: 400px; margin: 20px auto; font-family: Arial;">

      <h2>Görev Yöneticisi (Lab v1)</h2>

     

      <div style="margin-bottom: 15px;">

        <input [(ngModel)]="yeniGorevBaslik" placeholder="Yeni görev yaz..." style="padding: 5px; width: 70%;">

        <button (click)="gorevEkle()" style="padding: 5px 10px;">Ekle</button>

      </div>

 

      @for (item of gorevListesi; track item.id) {

        <div style="padding: 10px; border-bottom: 1px solid #eee; display: flex; align-items: center;">

          <input type="checkbox" [(ngModel)]="item.tamamlandi" style="margin-right: 10px;">

          <span [style.text-decoration]="item.tamamlandi ? 'line-through' : 'none'">

            {{ item.baslik }}

          </span>

        </div>

      } @empty {

        <p>Listeniz boş! Harika, tüm işler bitti.</p>

      }

    </div>

  `

})

export class TaskManagerComponent {

  yeniGorevBaslik: string = '';

  gorevListesi: IGorev[] = [

    { id: 1, baslik: 'Angular 22 Kursu Dinle', tamamlandi: false },

    { id: 2, baslik: 'Kod Pratiği Yap', tamamlandi: true }

  ];

 

  gorevEkle() {

    if (this.yeniGorevBaslik.trim() !== '') {

      this.gorevListesi.push({

        id: Date.now(),

        baslik: this.yeniGorevBaslik,

        tamamlandi: false

      });

      this.yeniGorevBaslik = ''; // Temizle

    }

  }

}


PROJE 6: Hata Ayıklama Alıştırması (Debugging Workspace)

Amaç: Konsola log bırakma ve çalışma zamanı hatalarını inceleme düzeneği kurmak.

import { Component } from '@angular/core';

 

@Component({

  selector: 'app-debug-demo',

  standalone: true,

  template: `

    <div style="padding: 20px; background: #fff3cd; border: 1px solid #ffeeba;">

      <h3>Hata Ayıklama Deney Alanı</h3>

      <button (click)="guvenliIslem()">Güvenli Konsol İncelemesi</button>

      <button (click)="kritikHataFirlat()" style="background: red; color: white;">Hata Tetikle</button>

    </div>

  `

})

export class DebugDemoComponent {

 

  guvenliIslem() {

    console.log('%c[DEBUG] İşlem adımı tetiklendi, veriler kontrol ediliyor...', 'color: blue; font-weight: bold;');

    // Chrome DevTools F12 -> Sources kısmında izlemek için debugger satırı:

    debugger;

  }

 

  kritikHataFirlat() {

    console.error('[HATA] Sunucu bağlantısı simüle edilerek kesildi!');

    throw new Error('Uygulama çalışma zamanı yapay hatası.');

  }

}


PROJE 7: Servisler ve Bağımlılık Enjeksiyonu (Services & inject())

Amaç: İş mantığını bileşenden ayırıp modern inject yapısıyla merkezi servisten tüketmek.

// src/app/log.service.ts

import { Injectable } from '@angular/core';

 

@Injectable({

  providedIn: 'root'

})

export class LogService {

  private logGecmisi: string[] = [];

 

  sistemeYaz(mesaj: string): void {

    const zamanliMesaj = `[${new Date().toLocaleTimeString()}] ${mesaj}`;

    this.logGecmisi.push(zamanliMesaj);

    console.log(zamanliMesaj);

  }

 

  tumLoglariGetir(): string[] {

    return this.logGecmisi;

  }

}

 

// src/app/servis-test.component.ts

import { Component, inject, OnInit } from '@angular/core';

import { LogService } from './log.service';

 

@Component({

  selector: 'app-service-demo',

  standalone: true,

  template: `

    <div style="padding: 15px; background: #e2e3e5;">

      <h3>Merkezi Servis ve Bağımlılık Enjeksiyonu</h3>

      <button (click)="islemYap()">Yeni Log Üret</button>

     

      <h4>Aktivite Geçmişi:</h4>

      @for (l of aktifLoglar; track $index) {

        <p style="font-family: monospace; font-size: 12px; margin: 3px 0;">{{ l }}</p>

      }

    </div>

  `

})

export class ServisTestComponent implements OnInit {

  // Angular 22 Constructor yerine inject() kullanım standardı

  private logger = inject(LogService);

  aktifLoglar: string[] = [];

 

  ngOnInit() {

    this.logger.sistemeYaz('Bileşen başarıyla initialize edildi.');

    this.aktifLoglar = this.logger.tumLoglariGetir();

  }

 

  islemYap() {

    this.logger.sistemeYaz('Kullanıcı buton aksiyonunu tetikledi.');

    this.aktifLoglar = this.logger.tumLoglariGetir();

  }

}


PROJE 8: Özel Boru Filtresi Yapımı (Custom Pipes)

Amaç: Ham veriyi ekrana basarken anlık manipüle eden saf ve saf olmayan filtre yapısı kurmak.

// src/app/maske.pipe.ts

import { Pipe, PipeTransform } from '@angular/core';

 

@Pipe({

  name: 'krediKartiMaske',

  standalone: true

})

export class KrediKartiMaskePipe implements PipeTransform {

  transform(value: string): string {

    if (!value || value.length < 16) return value;

    // İlk 4 haneyi göster, kalanları yıldızla, son 4 haneyi göster

    return value.substring(0, 4) + ' **** **** ' + value.substring(12);

  }

}

 

// src/app/pipe-demo.component.ts

import { Component } from '@angular/core';

import { KrediKartiMaskePipe } from './maske.pipe';

import { CurrencyPipe, DatePipe } from '@angular/common';

 

@Component({

  selector: 'app-pipe-demo',

  standalone: true,

  imports: [KrediKartiMaskePipe, CurrencyPipe, DatePipe],

  template: `

    <div style="padding: 15px; border: 1px dashed purple;">

      <h3>Veri Biçimlendirme (Pipes)</h3>

      <p><strong>Kart Numarası (Maskeli):</strong> {{ kartNo | krediKartiMaske }}</p>

      <p><strong>Bakiye Borç:</strong> {{ bakiye | currency:'TRY':'symbol':'1.2-2' }}</p>

      <p><strong>Son Güncelleme Zamanı:</strong> {{ bugun | date:'dd/MM/yyyy HH:mm' }}</p>

    </div>

  `

})

export class PipeDemoComponent {

  kartNo: string = '4355123456789012';

  bakiye: number = 14500.75;

  bugun: Date = new Date();

}


PROJE 9: HTTP İletişimi Simülasyonu (HttpClient API Mock)

Amaç: HttpClient kullanarak dış dünyadan veri çekme ve asenkron veri akış yönetimi.

// src/app/api.service.ts

import { Injectable, inject } from '@angular/core';

import { HttpClient } from '@angular/common/http';

import { Observable } from 'rxjs';

 

export interface IPost {

  id: number;

  title: string;

  body: string;

}

 

@Injectable({ providedIn: 'root' })

export class ApiService {

  private http = inject(HttpClient);

  private endpoint = 'https://typicode.com';

 

  getYazilar(): Observable<IPost[]> {

    return this.http.get<IPost[]>(this.endpoint);

  }

}

 

// src/app/http-demo.component.ts

import { Component, inject, OnInit } from '@angular/core';

import { ApiService, IPost } from './api.service';

 

@Component({

  selector: 'app-http-demo',

  standalone: true,

  template: `

    <div style="padding: 20px;">

      <h3>REST API Veri Akışı (HttpClient)</h3>

     

      @if (yukleniyor) {

        <p>Uzak sunucudan veriler indiriliyor...</p>

      }

 

      <div style="max-height: 200px; overflow-y: scroll; border: 1px solid #aaa; padding: 10px;">

        @for (post of veriListesi; track post.id) {

          <div style="background: #f9f9f9; margin-bottom: 5px; padding: 5px;">

            <strong>{{ post.title }}</strong>

            <p style="font-size:12px; margin:2px 0;">{{ post.body }}</p>

          </div>

        }

      </div>

    </div>

  `

})

export class HttpDemoComponent implements OnInit {

  private api = inject(ApiService);

  veriListesi: IPost[] = [];

  yukleniyor: boolean = true;

 

  ngOnInit() {

    this.api.getYazilar().subscribe({

      next: (res) => {

        this.veriListesi = res.slice(0, 5); // İlk 5 veriyi alalım

        this.yukleniyor = false;

      },

      error: (err) => {

        console.error('Hata oluştu:', err);

        this.yukleniyor = false;

      }

    });

  }

}


PROJE 10: Dinamik Veri Grid Yönetimi (Data Grid - Debounce & Sort)

Amaç: Girdi esnasında sistemi yormayan (Debounce) arama motorlu ve filtreli veri tablosu grid altyapısı.

import { Component, OnInit } from '@angular/core';

import { Subject } from 'rxjs';

import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

import { FormsModule } from '@angular/forms';

 

interface ICalisan { id: number; isim: string; departman: string; }

 

@Component({

  selector: 'app-data-grid',

  standalone: true,

  imports: [FormsModule],

  template: `

    <div style="padding:20px;">

      <h3>Gelişmiş Çalışan Grid Tablosu</h3>

     

      <input [(ngModel)]="aramaKriteri" (input)="aramaTetiklendi()" placeholder="Hızlı ara (Debounce aktif)..." style="padding:6px; margin-bottom:10px; width:250px;">

     

      <table border="1" cellpadding="5" style="border-collapse: collapse; width:100%;">

        <thead style="background:#eee;">

          <tr>

            <th>ID</th>

            <th (click)="sirala()" style="cursor:pointer; color:blue;">İsim (Sırala ▲▼)</th>

            <th>Departman</th>

          </tr>

        </thead>

        <tbody>

          @for (c of filtrelenmişListe; track c.id) {

            <tr>

              <td>{{ c.id }}</td>

              <td>{{ c.isim }}</td>

              <td>{{ c.departman }}</td>

            </tr>

          }

        </tbody>

      </table>

    </div>

  `

})

export class DataGridComponent implements OnInit {

  aramaKriteri: string = '';

  private aramaAkisi = new Subject<string>();

 

  hamListe: ICalisan[] = [

    { id: 1, isim: 'Ahmet Yılmaz', departman: 'Ar-Ge' },

    { id: 2, isim: 'Zeynep Kaya', departman: 'İK' },

    { id: 3, isim: 'Can Demir', departman: 'Finans' }

  ];

  filtrelenmişListe: ICalisan[] = [];

  duzSiralama: boolean = true;

 

  ngOnInit() {

    this.filtrelenmişListe = [...this.hamListe];

 

    // Debounce mekanizması kurulumu

    this.aramaAkisi.pipe(

      debounceTime(400), // Kullanıcı yazmayı bıraktıktan sonra 400ms bekle

      distinctUntilChanged() // Sadece veri gerçekten değiştiyse tetikle

    ).subscribe(metin => {

      this.filtrelenmişListe = this.hamListe.filter(c =>

        c.isim.toLowerCase().includes(metin.toLowerCase())

      );

    });

  }

 

  aramaTetiklendi() {

    this.aramaAkisi.next(this.aramaKriteri);

  }

 

  sirala() {

    this.duzSiralama = !this.duzSiralama;

    this.filtrelenmişListe.sort((a, b) =>

      this.duzSiralama ? a.isim.localeCompare(b.isim) : b.isim.localeCompare(a.isim)

    );

  }

}


PROJE 11: Şablon Odaklı Form Yapısı (Template Driven Forms)

Amaç: HTML attributes üzerinden hızlı validasyonlu basit form tasarımı ve state kontrolü.

import { Component } from '@angular/core';

import { FormsModule, NgForm } from '@angular/forms';

 

@Component({

  selector: 'app-template-form',

  standalone: true,

  imports: [FormsModule],

  template: `

    <div style="max-width:350px; padding:20px; border:1px solid #ccc; margin:10px;">

      <h4>Giriş Yap (Template Driven)</h4>

     

      <form #f="ngForm" (ngSubmit)="formuGonder(f)">

        <div style="margin-bottom:10px;">

          <label>E-Posta: </label><br>

          <input type="email" name="email" ngModel required email #emailModel="ngForm">

          @if (emailModel.invalid && emailModel.touched) {

            <br><small style="color:red;">Geçerli e-posta zorunludur!</small>

          }

        </div>

 

        <div style="margin-bottom:10px;">

          <label>Şifre: </label><br>

          <input type="password" name="sifre" ngModel required minlength="4" #sifreModel="ngForm">

          @if (sifreModel.invalid && sifreModel.touched) {

            <br><small style="color:red;">Şifre en az 4 hane olmalı!</small>

          }

        </div>

 

        <button type="submit" [disabled]="f.invalid">Giriş Yap</button>

      </form>

    </div>

  `

})

export class TemplateFormComponent {

  formuGonder(formNesnesi: NgForm) {

    if (formNesnesi.valid) {

      console.log('Form Başarıyla Gönderildi:', formNesnesi.value);

    }

  }

}


PROJE 12: Reaktif Form Teknolojisi (Reactive Forms)

Amaç: TypeScript kod blokları üzerinden tam denetimli dinamik form takibi ve doğrulamalar.

import { Component, inject } from '@angular/core';

import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';

 

@Component({

  selector: 'app-reactive-form',

  standalone: true,

  imports: [ReactiveFormsModule],

  template: `

    <div style="max-width:350px; padding:20px; border:1px solid blue; margin:10px;">

      <h4>Ürün Ekleme (Reactive Form)</h4>

     

      <form [formGroup]="urunFormu" (ngSubmit)="kaydet()">

        <div style="margin-bottom:10px;">

          <label>Ürün Adı:</label><br>

          <input formControlName="urunAdi">

          @if (urunFormu.get('urunAdi')?.invalid && urunFormu.get('urunAdi')?.touched) {

            <br><small style="color:red;">Ürün adı en az 3 karakter olmalı!</small>

          }

        </div>

 

        <div style="margin-bottom:10px;">

          <label>Stok Adedi:</label><br>

          <input type="number" formControlName="stok">

        </div>

 

        <button type="submit" [disabled]="urunFormu.invalid">Formu Kaydet</button>

      </form>

    </div>

  `

})

export class ReactiveFormComponent {

  private fb = inject(FormBuilder);

 

  urunFormu = this.fb.group({

    urunAdi: ['', [Validators.required, Validators.minLength(3)]],

    stok: [10, [Validators.required, Validators.min(1)]]

  });

 

  kaydet() {

    if (this.urunFormu.valid) {

      console.log('Reaktif Form Verisi Çıktısı:', this.urunFormu.value);

    }

  }

}


PROJE 13: Görsel Arayüz Elemanları Örneği (Angular Material UI Custom Layout)

Amaç: Angular Material mimarisine uygun şık kart ve buton yapılarının işlevsel simülasyonu.

import { Component } from '@angular/core';

 

@Component({

  selector: 'app-material-mock',

  standalone: true,

  template: `

    <div style="padding: 20px; font-family: Roboto, sans-serif;">

      <!-- MatToolbar Simülasyonu -->

      <div style="background:#673ab7; color:white; padding:15px; font-weight:bold; border-radius:4px 4px 0 0;">

        Material Dashboard Panel

      </div>

     

      <!-- MatCard Simülasyonu -->

      <div style="box-shadow: 0 4px 8px rgba(0,0,0,0.1); border:1px solid #e0e0e0; padding:20px; background:white; margin-top:15px; border-radius:4px;">

        <h3 style="margin-top:0;">MatCard Başlığı</h3>

        <p style="color:#666;">Sistem analitiği ve raporlama grafikleri aşağıda listelenmiştir.</p>

        <hr style="border:0; border-top:1px solid #eee;">

       

        <!-- MatButton Örnekleri -->

        <button style="background:#ff4081; color:white; border:none; padding:8px 16px; border-radius:4px; font-weight:bold; cursor:pointer; margin-right:10px;">

          ONAYLA (RAISED)

        </button>

        <button style="background:transparent; color:#673ab7; border:1px solid #673ab7; padding:8px 16px; border-radius:4px; cursor:pointer;">

          İPTAL (OUTLINED)

        </button>

      </div>

    </div>

  `

})

export class MaterialMockComponent {}


PROJE 14: Bileşen Yaşam Döngüsü İzleme İstasyonu (Component Lifecycle Hooks)

Amaç: Bir bileşenin doğuşundan ölümüne kadarki tüm evrelerini (Init, Destroy) konsolda yakalamak.

// src/app/lifecycle-child.component.ts

import { Component, OnInit, OnDestroy, Input, OnChanges, SimpleChanges } from '@angular/core';

 

@Component({

  selector: 'app-lifecycle-child',

  standalone: true,

  template: `<div style="background:#d4edda; padding:10px;">Sayaç Değeri: {{ sayiGirdisi }}</div>`

})

export class LifecycleChildComponent implements OnInit, OnDestroy, OnChanges {

  @Input() sayiGirdisi: number = 0;

 

  ngOnChanges(changes: SimpleChanges) {

    console.log('[LIFECYCLE] ngOnChanges tetiklendi. Eski/Yeni değer:', changes);

  }

 

  ngOnInit() {

    console.log('[LIFECYCLE] child-component doğdu (ngOnInit).');

  }

 

  ngOnDestroy() {

    console.log('[LIFECYCLE] child-component yok edildi (ngOnDestroy temizliği).');

  }

}

 

// src/app/lifecycle-parent.component.ts

import { Component } from '@angular/core';

import { LifecycleChildComponent } from './lifecycle-child.component';

 

@Component({

  selector: 'app-lifecycle-parent',

  standalone: true,

  imports: [LifecycleChildComponent],

  template: `

    <div style="padding:20px; border:1px solid green;">

      <h3>Yaşam Döngüsü Denetleyicisi (F12 Konsolunu İzleyin)</h3>

      <button (click)="artir()">Girdiyi Değiştir (ngOnChanges Tetikle)</button>

      <button (click)="Kapat()" style="background:orange;">Alt Bileşeni Kapat (ngOnDestroy Tetikle)</button>

      <hr>

      @if (bilesenAktif) {

        <app-lifecycle-child [sayiGirdisi]="sayac"></app-lifecycle-child>

      }

    </div>

  `

})

export class LifecycleParentComponent {

  sayac: number = 0;

  bilesenAktif: boolean = true;

 

  artir() { this.sayac++; }

  Kapat() { this.bilesenAktif = !this.bilesenAktif; }

}


PROJE 15: Güvenlik, Kimlik Doğrulama ve CanActivate Guard (Security & Guards)

Amaç: Yetkisiz kullanıcıların yönetim sayfalarına erişmesini engelleyen router koruma mekanizması kurmak.

// src/app/auth.service.ts

import { Injectable } from '@angular/core';

 

@Injectable({ providedIn: 'root' })

export class AuthService {

  private girisYapildiMi: boolean = false;

 

  oturumAc() { this.girisYapildiMi = true; }

  oturumKapat() { this.girisYapildiMi = false; }

 

  isLoggedIn(): boolean {

    return this.girisYapildiMi;

  }

}

 

// src/app/auth.guard.ts

import { inject } from '@angular/core';

import { CanActivateFn, Router } from '@angular/router';

import { AuthService } from './auth.service';

 

export const adminGuard: CanActivateFn = (route, state) => {

  const auth = inject(AuthService);

  const router = inject(Router);

 

  if (auth.isLoggedIn()) {

    return true; // Giriş izni ver

  } else {

    alert('Erişim Engellendi! Önce oturum açmalısınız.');

    router.navigate(['/giris']);

    return false; // Geçişi blokla

  }

};

 

// src/app/auth-demo.component.ts

import { Component, inject } from '@angular/core';

import { AuthService } from './auth.service';

 

@Component({

  selector: 'app-auth-demo',

  standalone: true,

  template: `

    <div style="padding:20px; background:#f8d7da; border:1px solid #f5c6cb;">

      <h3>Güvenlik Duvarı ve JWT Simülasyonu</h3>

      <p><strong>Mevcut Durum:</strong> {{ auth.isLoggedIn() ? 'Oturum Açık' : 'Ziyaretçi' }}</p>

     

      <button (click)="auth.oturumAc()">Sisteme Giriş Yap (Token Al)</button>

      <button (click)="auth.oturumKapat()">Güvenli Çıkış Yap</button>

    </div>

  `

})

export class AuthDemoComponent {

  public auth = inject(AuthService);

}

 

 

Bu 15 farklı mini projeyi bilgisayarınızda tek bir çatı altında birleştirmek, aralarında sorunsuz geçiş yapmak ve projeyi ayağa kaldırmak için gereken tüm entegrasyon adımlarını ve ana kontrol panelini (Dashboard) hazırladım.

Aşağıdaki adımları sırasıyla uygulayarak tüm sistemi tek seferde çalıştırabilirsiniz.


BÖLÜM 1: Uygulamayı Kurma ve Çalıştırma Adımları (CLI Komutları)

Bilgisayarınızda boş bir klasör açın, komut satırını (Terminal / CMD) başlatın ve şu komutları sırasıyla yazın:

# 1. En güncel Angular CLI aracını bilgisayarınıza genel olarak kurun

npm install -g @angular/cli

 

# 2. "angular-masterclass" adında yeni ve bağımsız (Standalone) bir proje oluşturun

ng new angular-masterclass --routing --style=css --standalone

 

# 3. Oluşturulan proje klasörünün içerisine giriş yapın

cd angular-masterclass

 

# 4. Projenin yerel sunucusunu başlatın ve tarayıcıda (http://localhost:4200) otomatik açın

ng serve --open


BÖLÜM 2: Proje Kodlarının Entegrasyonu

Projelerin hatasız derlenmesi için gerekli olan ortak yönlendirme (Routing) ve konfigürasyon dosyalarını güncelleyelim.

1. Rotaların Tanımlanması

Projenizdeki src/app/app.routes.ts dosyasını açın ve içeriğini aşağıdaki gibi düzenleyin. Bu sayfa, menüden tıklandığında hangi projenin ekrana geleceğini belirler.

// src/app/app.routes.ts

import { Routes } from '@angular/router';

import { adminGuard } from './auth.service'; // Proje 15 koruması

 

export const routes: Routes = [

  {

    path: 'proje1',

    loadComponent: () => import('./app.component').then(m => m.AppComponent)

  },

  {

    path: 'proje2',

    loadComponent: () => import('./typescript-demo.component').then(m => m.TypescriptDemoComponent)

  },

  {

    path: 'proje4',

    loadComponent: () => import('./binding-demo.component').then(m => m.BindingDemoComponent)

  },

  {

    path: 'proje5',

    loadComponent: () => import('./task-manager.component').then(m => m.TaskManagerComponent)

  },

  {

    path: 'proje6',

    loadComponent: () => import('./debug-demo.component').then(m => m.DebugDemoComponent)

  },

  {

    path: 'proje7',

    loadComponent: () => import('./servis-test.component').then(m => m.ServisTestComponent)

  },

  {

    path: 'proje8',

    loadComponent: () => import('./pipe-demo.component').then(m => m.PipeDemoComponent)

  },

  {

    path: 'proje9',

    loadComponent: () => import('./http-demo.component').then(m => m.HttpDemoComponent)

  },

  {

    path: 'proje10',

    loadComponent: () => import('./data-grid.component').then(m => m.DataGridComponent)

  },

  {

    path: 'proje11',

    loadComponent: () => import('./template-form.component').then(m => m.TemplateFormComponent)

  },

  {

    path: 'proje12',

    loadComponent: () => import('./reactive-form.component').then(m => m.ReactiveFormComponent)

  },

  {

    path: 'proje13',

    loadComponent: () => import('./material-mock.component').then(m => m.MaterialMockComponent)

  },

  {

    path: 'proje14',

    loadComponent: () => import('./lifecycle-parent.component').then(m => m.LifecycleParentComponent)

  },

  {

    path: 'proje15',

    loadComponent: () => import('./auth-demo.component').then(m => m.AuthDemoComponent)

  },

  // Proje 15 Güvenlik Duvarı ile korunan Örnek Gizli Yönetim Paneli Sayfası

  {

    path: 'gizli-panel',

    canActivate: [adminGuard],

    loadComponent: () => import('./material-mock.component').then(m => m.MaterialMockComponent)

  }

];

2. HTTP İletişim Sağlayıcısının Eklenmesi

Proje 9 ve 10'da kullandığımız HttpClient yapısının çalışabilmesi için src/app/app.config.ts dosyanıza provideHttpClient() metodunu eklemeniz gerekir.

// src/app/app.config.ts

import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';

import { provideRouter } from '@angular/router';

import { provideHttpClient } from '@angular/common/http';

import { routes } from './app.routes';

 

export const appConfig: ApplicationConfig = {

  providers: [

    provideZoneChangeDetection({ eventCoalescing: true }),

    provideRouter(routes),

    provideHttpClient() // HTTP isteklerini tüm projede aktif eder

  ]

};


BÖLÜM 3: Ana Yönetim Menüsü (Dashboard) HTML ve Mimarisi

Bütün projeleri tek bir ekrandan yönetebileceğiniz, sol tarafı menü, sağ tarafı ise dinamik içerik alanı olan profesyonel Dashboard yapısı.

src/app/app.component.ts dosyanızın içeriğini silip aşağıdaki komple entegre kodla değiştirin:

// src/app/app.component.ts

import { Component } from '@angular/core';

import { RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router';

 

@Component({

  selector: 'app-root',

  standalone: true,

  imports: [RouterOutlet, RouterLink, RouterLinkActive],

  template: `

    <div class="dashboard-container">

      <!-- SOL MENÜ PANELİ -->

      <aside class="sidebar">

        <div class="sidebar-header">

          <h2>Angular 22</h2>

          <span class="badge">Masterclass</span>

        </div>

       

        <nav class="menu-list">

          <a routerLink="/proje1" routerLinkActive="active-menu">📁 1. Giriş & Mimari</a>

          <a routerLink="/proje2" routerLinkActive="active-menu">⚙️ 2. TypeScript Yapıları</a>

          <a routerLink="/proje4" routerLinkActive="active-menu">🔗 4. Veri Bağlama (Bindings)</a>

          <a routerLink="/proje5" routerLinkActive="active-menu">✅ 5. Görev Yöneticisi (Lab)</a>

          <a routerLink="/proje6" routerLinkActive="active-menu">🪲 6. Hata Ayıklama Paneli</a>

          <a routerLink="/proje7" routerLinkActive="active-menu">🛠️ 7. inject() Servis Yapısı</a>

          <a routerLink="/proje8" routerLinkActive="active-menu">💎 8. Özel Filtreler (Pipes)</a>

          <a routerLink="/proje9" routerLinkActive="active-menu">🌐 9. HTTP Sunucu İletişimi</a>

          <a routerLink="/proje10" routerLinkActive="active-menu">📊 10. Gelişmiş Data Grid</a>

          <a routerLink="/proje11" routerLinkActive="active-menu">📝 11. Template Form</a>

          <a routerLink="/proje12" routerLinkActive="active-menu">🧬 12. Reactive Form</a>

          <a routerLink="/proje13" routerLinkActive="active-menu">🎨 13. Material Tasarımları</a>

          <a routerLink="/proje14" routerLinkActive="active-menu">🔄 14. Lifecycle Hooks</a>

          <a routerLink="/proje15" routerLinkActive="active-menu">🔐 15. Güvenlik & Token</a>

          <a routerLink="/gizli-panel" routerLinkActive="active-menu" class="lock-link">🛑 Korunan Gizli Sayfa</a>

        </nav>

      </aside>

 

      <!-- SAĞ DİNAMİK İÇERİK ALANI -->

      <main class="main-content">

        <header class="top-bar">

          <h3>Proje İzleme ve Canlı Çalıştırma İstasyonu</h3>

          <div class="status-indicator">

            <span class="dot"></span> Sistem Aktif (Port: 4200)

          </div>

        </header>

       

        <!-- Seçilen alt mini proje dinamik olarak buraya yüklenecektir -->

        <section class="stage">

          <router-outlet></router-outlet>

        </section>

      </main>

    </div>

  `,

  styles: [`

    /* Dashboard Genel Arayüz Tasarımı */

    .dashboard-container {

      display: flex;

      height: 100vh;

      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

      background-color: #f4f6f9;

      margin: 0;

    }

 

    /* Sol Menü Tasarımı */

    .sidebar {

      width: 280px;

      background-color: #1e293b;

      color: #cbd5e1;

      display: flex;

      flex-direction: column;

      box-shadow: 2px 0 10px rgba(0,0,0,0.1);

    }

 

    .sidebar-header {

      padding: 20px;

      background-color: #0f172a;

      text-align: center;

      border-bottom: 1px solid #334155;

    }

 

    .sidebar-header h2 {

      margin: 0;

      color: #fff;

      font-size: 22px;

    }

 

    .badge {

      font-size: 11px;

      background: #3b82f6;

      color: white;

      padding: 2px 8px;

      border-radius: 10px;

      margin-top: 5px;

      display: inline-block;

    }

 

    .menu-list {

      display: flex;

      flex-direction: column;

      padding: 15px 0;

      overflow-y: auto;

    }

 

    .menu-list a {

      color: #94a3b8;

      text-decoration: none;

      padding: 12px 25px;

      font-size: 14px;

      display: flex;

      align-items: center;

      transition: all 0.2s ease;

    }

 

    .menu-list a:hover {

      background-color: #334155;

      color: #fff;

    }

 

    /* Tıklanan Aktif Menüyü Boyama */

    .active-menu {

      background-color: #2563eb !important;

      color: #fff !important;

      font-weight: bold;

      border-left: 5px solid #60a5fa;

    }

 

    .lock-link {

      border-top: 1px dashed #475569;

      margin-top: 10px;

      color: #f87171 !important;

    }

 

    /* Sağ İçerik Alanı */

    .main-content {

      flex: 1;

      display: flex;

      flex-direction: column;

      overflow: hidden;

    }

 

    .top-bar {

      background-color: #fff;

      height: 60px;

      display: flex;

      align-items: center;

      justify-content: space-between;

      padding: 0 30px;

      border-bottom: 1px solid #e2e8f0;

    }

 

    .top-bar h3 {

      margin: 0;

      color: #334155;

      font-size: 16px;

    }

 

    .status-indicator {

      font-size: 13px;

      color: #10b981;

      display: flex;

      align-items: center;

    }

 

    .dot {

      height: 8px;

      width: 8px;

      background-color: #10b981;

      border-radius: 50%;

      display: inline-block;

      margin-right: 8px;

      animation: pulse 1.5s infinite;

    }

 

    .stage {

      flex: 1;

      padding: 30px;

      overflow-y: auto;

    }

 

    @keyframes pulse {

      0% { transform: scale(0.9); opacity: 0.7; }

      50% { transform: scale(1.1); opacity: 1; }

      100% { transform: scale(0.9); opacity: 0.7; }

    }

  `]

})

export class AppComponent {}


BÖLÜM 4: Şimdi Ne Olacak?

Sistem tamamen hazır hale geldi. ng serve komutu çalıştıktan sonra tarayıcınızda sol taraftaki menü butonlarına tıkladığınız anda:

  1. Seçtiğiniz konunun mini projesi sağ taraftaki beyaz alana (<router-outlet>) anında yüklenir.
  2. Sayfa yenilenmeden, state kaybolmadan tüm uygulamaları canlı simülasyon olarak test edebilirsiniz.
  3. Proje 15'e gidip "Sisteme Giriş Yap" butonuna basmadan en alttaki "Korunan Gizli Sayfa" linkine tıklarsanız, sistemin sizi guard mekanizmasıyla nasıl engellediğini canlı olarak görebilirsiniz.

 

 

"Öğrenecekleriniz" Bölümünün Açıklaması

Gönderdiğiniz kursta Öğrenecekleriniz başlığı altındaki maddeler, modern bir ön yüz (frontend) geliştiricisi olmak için ihtiyacınız olan tüm temel ve ileri düzey Angular yeteneklerini özetlemektedir:


Konu Tasarımı ve Planlama

Eğitim içeriğini mantıksal bir sıra ile 7 ana bölüme ayırarak tasarlıyoruz. Her başlığı sırasıyla teorik altyapısı, pratik kod örnekleri ve gerçekçi uygulama adımlarıyla ele alacağız.

+-------------------------------------------------------------+

 

|               Modern Angular Geliştirme Haritası            |

+-------------------------------------------------------------+

                               |

       +-----------------------+-----------------------+

 

       |                                               |

[1. Temel Mimariler]                            [2. Veri ve Tepkisellik]

 - Bağımsız Bileşenler                           - Sinyaller (Signals)

 - Şablonlar & Bağlamalar                        - Gelişmiş Veri Akışları

 

       |                                               |

       +-----------------------+-----------------------+

                               |

       +-----------------------+-----------------------+

 

       |                                               |

[3. Dinamik Yapılar]                            [4. Dış Dünya ile İletişim]

 - Özel Direktifler                              - HttpClient API Kontrolü

 - Boru Hatları (Pipes)                          - İnterseptör Yapıları

 

       |                                               |

       +-----------------------+-----------------------+

                               |

       +-----------------------+-----------------------+

 

       |                                               |

[5. Kullanıcı Etkileşimi]                       [6. Sayfa Yönetimi & Güvenlik]

 - Sinyal Tabanlı Formlar                        - Akıllı Yönlendirme (Routing)

 - Gelişmiş Doğrulamalar                         - Sayfa Koruyucular (Guards)

                               |

             +-----------------+-----------------+

 

             |                                   |

      [7. Mimari Optimizasyon]            [8. Test Stratejileri]

       - Performans & Kod Bölme            - Birim Testleri (Unit Test)


Tüm Konuların Detaylı Açıklaması, Örnekleri ve Uygulamaları


1. Temel Mimari: Bağımsız Bileşenler (Standalone Components) ve Şablonlar

Angular uygulamalarının en küçük yapı taşına Bileşen (Component) adı verilir. Eski Angular versiyonlarında her bileşeni bir modüle (NgModule) kayıt etmek zorundaydık. Modern Angular dünyasında ise her bileşen Bağımsız (Standalone) olarak tanımlanır. Kendi bağımlılıklarını kendisi ithal eder. [1, 2, 8]

Bileşen Bağlama Türleri (Data Binding)

Uygulama Örneği: Ürün Kartı Bileşeni

Bir e-ticaret sitesi için bağımsız bir ürün kartı bileşeni tasarlayalım. Bu bileşen hem bilgileri ekrana bassın, hem resmi dinamik alsın, hem de tıklama olayını yakalasın.

TypeScript Kod Dosyası (urun-kart.component.ts)

import { Component } from '@angular/core';

import { CommonModule } from '@angular/common';

import { FormsModule } from '@angular/forms';

 

@Component({

  selector: 'app-urun-kart',

  standalone: true, // Modüle ihtiyaç duymadığını belirtir

  imports: [CommonModule, FormsModule], // Kullanacağı ek özellikleri buraya ekler

  templateUrl: './urun-kart.component.html',

  styleUrls: ['./urun-kart.component.css']

})

export class UrunKartComponent {

  urunAdi: string = 'Kablosuz Oyuncu Kulaklığı';

  urunResmi: string = 'https://picsum.photos';

  stokAdedi: number = 5;

  kullaniciNotu: string = '';

 

  stokAzalt() {

    if (this.stokAdedi > 0) {

      this.stokAdedi--;

    }

  }

}

HTML Şablon Dosyası (urun-kart.component.html)

<div class="kart">

  <!-- String Interpolation -->

  <h2>{{ urunAdi }}</h2>

 

  <!-- Property Binding -->

  <img [src]="urunResmi" alt="Ürün Resmi">

 

  <p>Mevcut Stok: {{ stokAdedi }}</p>

 

  <!-- Event Binding -->

  <button (click)="stokAzalt()" [disabled]="stokAdedi === 0">Satın Al</button>

 

  <!-- Two-Way Binding -->

  <div class="not-alani">

    <input [(ngModel)]="kullaniciNotu" placeholder="Sipariş notu yazın...">

    <p>Notunuz: <i>{{ kullaniciNotu }}</i></p>

  </div>

</div>


2. Tepkisel Yönetim: Sinyaller (Signals) ve Gelişmiş Veri Akışı

Sinyaller (Signals), Angular'da verinin değiştiğini sisteme çok hızlı bildiren akıllı veri kutularıdır. Eski sistemde Angular bir değişkenin değişip değişmediğini anlamak için bütün sayfayı baştan aşağı kontrol ederdi (Change Detection). Sinyaller sayesinde sadece o verinin kullanıldığı nokta tespit edilir ve ışık hızında güncellenir. [3, 4]

Uygulama Örneği: Akıllı Alışveriş Sepeti Hesaplayıcısı

TypeScript Kod Dosyası (sepet.component.ts)

import { Component, signal, computed, effect } from '@angular/core';

 

@Component({

  selector: 'app-sepet',

  standalone: true,

  template: `

    <div>

      <h3>Alışveriş Sepetim</h3>

      <p>Ürün Fiyatı: {{ urunFiyati() }} TL</p>

      <p>Adet: {{ adet() }}</p>

     

      <button (click)="artir()">+</button>

      <button (click)="azalt()">-</button>

     

      <h4>Toplam Tutar: {{ toplamTutar() }} TL</h4>

    </div>

  `

})

export class SepetComponent {

  // Sinyal tanımlamaları

  urunFiyati = signal<number>(150);

  adet = signal<number>(1);

 

  // Computed sinyal: adet veya urunFiyati değiştiğinde otomatik hesaplanır

  toplamTutar = computed(() => this.urunFiyati() * this.adet());

 

  constructor() {

    // Effect kullanımı: Değişimleri izler ve konsola yazar

    effect(() => {

      console.log(`Sepet güncellendi! Yeni adet: ${this.adet()}, Toplam: ${this.toplamTutar()} TL`);

    });

  }

 

  artir() {

    this.adet.update(mevcut => mevcut + 1);

  }

 

  azalt() {

    if (this.adet() > 1) {

      this.adet.update(mevcut => mevcut - 1);

    }

  }

}


3. Dinamik Yapılar: Özel Direktifler (Directives) ve Boru Hatları (Pipes)

Direktifler (Directives)

HTML etiketlerinin davranışlarını veya görünümlerini değiştiren yapılardır. İki çeşittir:

  1. Structural (Yapısal - @if, @for): HTML etiketini sayfaya ekler veya siler.
  2. Attribute (Özellik): Etiketin rengini, stilini veya arka planını manipüle eder. [1]

Boru Hatları (Pipes)

Ekrandaki veriyi kullanıcının göreceği formata sokar. Örneğin ham bir tarihi 25/08/2026 şekline veya bir yazıyı tamamen BÜYÜK HARFE çevirir.

Uygulama Örneği: Özel Parlama Direktifi ve Para Birimi Filtresi

Hem üzerine gelindiğinde rengi değiştiren bir direktif yazalım, hem de sayıları Türkçe para formatına çeviren bir Pipe kullanalım.

Özel Direktif Kodu (parla.directive.ts)

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

 

@Directive({

  selector: '[appParla]',

  standalone: true

})

export class ParlaDirective {

  @Input() parlamaRengi: string = 'yellow';

 

  constructor(private el: ElementRef) {}

 

  @HostListener('mouseenter') uzerineGeldi() {

    this.el.nativeElement.style.backgroundColor = this.parlamaRengi;

  }

 

  @HostListener('mouseleave') uzerindenGitti() {

    this.el.nativeElement.style.backgroundColor = null;

  }

}

Bileşende Kullanımı (liste.component.ts)

import { Component } from '@angular/core';

import { CommonModule } from '@angular/common';

import { ParlaDirective } from './parla.directive';

 

@Component({

  selector: 'app-liste',

  standalone: true,

  imports: [CommonModule, ParlaDirective],

  template: `

    <!-- Özel direktif ve Dahili Pipe kullanımı -->

    <div appParla parlamaRengi="lightblue" class="kutu">

      Dinamik Değer: {{ hamKazanc | currency:'TRY':'symbol':'1.2-2' }}

    </div>

 

    <h3>Kurs Katılımcıları</h3>

    <ul>

      <!-- Yeni Nesil @for Yapısı -->

      @for (kullanici of kullanicilar; track kullanici.id) {

        <li>{{ kullanici.isim }}</li>

      } @empty {

        <li>Kayıtlı kullanıcı bulunamadı.</li>

      }

    </ul>

  `

})

export class ListeComponent {

  hamKazanc: number = 1250.75;

  kullanicilar = [

    { id: 1, isim: 'Ahmet Yılmaz' },

    { id: 2, isim: 'Elif Kaya' }

  ];

}


4. Dış Dünya ile İletişim: Servisler ve HttpClient

Veri saklama, API'lere bağlanma veya backend sistemleri ile konuşma görevleri bileşenlerin içinde yapılmaz. Bu işler için Servis (Service) adı verilen merkezi yapılar kurulur. Bu servisler içinden HttpClient nesnesi kullanılarak uzak sunuculara veri gönderilir veya alınır. [2, 7]

Uygulama Örneği: Sunucudan Görev Listesi Çekme Uygulaması

Bir API sunucusundan veri çeken servis ve bunu ekrana basan bileşeni tasarlayalım.

Veri Servisi Dosyası (gorek.service.ts)

import { Injectable, inject } from '@angular/core';

import { HttpClient } from '@angular/common/http';

import { Observable } from 'rxjs';

 

export interface Gorek {

  id: number;

  title: string;

  completed: boolean;

}

 

@Injectable({

  providedIn: 'root' // Uygulamanın her yerinden erişilebilir yapar

})

export class GorekService {

  // Yeni nesil enjeksiyon yöntemi

  private http = inject(HttpClient);

  private apiUrl = 'https://typicode.com';

 

  gorevleriGetir(): Observable<Gorek[]> {

    return this.http.get<Gorek[]>(this.apiUrl);

  }

}

Bileşen Dosyası (gorev.component.ts)

import { Component, OnInit, inject, signal } from '@angular/core';

import { GorekService, Gorek } from './gorek.service';

 

@Component({

  selector: 'app-gorev',

  standalone: true,

  template: `

    <h2>Görev Planlayıcı</h2>

    @if (yukleniyor()) {

      <p>Veriler sunucudan yükleniyor...</p>

    }

 

    <ul>

      @for (g of gorevler(); track g.id) {

        <li>

          <input type="checkbox" [checked]="g.completed">

          {{ g.title }}

        </li>

      }

    </ul>

  `

})

export class GorevComponent implements OnInit {

  private gorevService = inject(GorekService);

 

  gorevler = signal<Gorek[]>([]);

  yukleniyor = signal<boolean>(true);

 

  ngOnInit() {

    this.gorevService.gorevleriGetir().subscribe({

      next: (gelenVeriler) => {

        this.gorevler.set(gelenVeriler);

        this.yukleniyor.set(false);

      },

      error: (hata) => {

        console.error('Veri çekilirken hata oluştu:', hata);

        this.yukleniyor.set(false);

      }

    });

  }

}


5. Kullanıcı Etkileşimi: Sinyal Tabanlı Formlar (Signal Forms)

Yeni nesil Angular mimarisinde form yönetimleri de Sinyal tabanlı hale getirilmiştir. form() API'si yardımıyla form alanlarının doluluk oranları, hata durumları ve değerleri tamamen sinyal fonksiyonları üzerinden asenkron aboneliklere (Subscription) ihtiyaç duymadan yönetilir. [3, 5, 9]

Uygulama Örneği: Güvenli Kayıt Olma Formu

TypeScript Kod Dosyası (kayit-form.component.ts)

import { Component, signal } from '@angular/core';

import { form, required, email, minLength } from '@angular/forms/signals';

 

@Component({

  selector: 'app-kayit-form',

  standalone: true,

  template: `

    <form (submit)="kaydet()">

      <div>

        <label>E-posta:</label>

        <input [formField]="userForm.email" type="email">

        @if (userForm.email.errors()?.required) { <span>Zorunlu alan!</span> }

      </div>

 

      <div>

        <label>Şifre:</label>

        <input [formField]="userForm.password" type="password">

        @if (userForm.password.errors()?.minLength) { <span>En az 6 karakter!</span> }

      </div>

 

      <button type="submit" [disabled]="userForm.invalid()">Kayıt Ol</button>

    </form>

  `

})

export class KayitFormComponent {

  // Form modeli sinyal olarak tanımlanır

  formModel = signal({

    email: '',

    password: ''

  });

 

  // Kurallar şema yardımıyla bağlanır

  userForm = form(this.formModel, (schema) => {

    required(schema.email);

    email(schema.email);

    required(schema.password);

    minLength(schema.password, 6);

  });

 

  kaydet() {

    if (this.userForm.valid()) {

      console.log('Sunucuya gönderilen veriler:', this.formModel());

    }

  }

}


6. Sayfa Yönetimi ve Güvenlik: Akıllı Yönlendirme (Routing) ve Sayfa Koruyucular (Guards)

Büyük web uygulamalarında kullanıcıların /anasayfa, /profil veya /ayarlar gibi adreslere gidebilmesi gerekir. Bağımsız bileşen yapısında yönlendirmeler provideRouter fonksiyonu ile ana uygulama ayağa kaldırılırken (bootstrap) sisteme enjekte edilir. Sayfaların yetkisiz kişilerce açılmasını engellemek için ise Fonksiyonel Guard (Koruyucu) yapıları kurgulanır. [6, 7, 10, 11, 12]

Uygulama Örneği: Güvenli Rota Yönetimi

Rota Tanımlama Dosyası (app.routes.ts)

import { Routes } from '@angular/router';

import { inject } from '@angular/core';

import { Router } from '@angular/router';

 

// Fake Giriş Kontrol Fonksiyonu (Guard)

const girisKontrolGuard = () => {

  const router = inject(Router);

  const girisYaptiMi = localStorage.getItem('isLoggedIn') === 'true';

 

  if (girisYaptiMi) {

    return true;

  } else {

    router.navigate(['/login']);

    return false;

  }

};

 

export const routes: Routes = [

  {

    path: 'login',

    loadComponent: () => import('./login.component').then(m => m.LoginComponent)

  },

  {

    path: 'panel',

    loadComponent: () => import('./panel.component').then(m => m.PanelComponent),

    canActivate: [girisKontrolGuard] // Sayfayı koruma altına alır

  },

  { path: '', redirectTo: 'login', pathMatch: 'full' }

];

Ana Uygulama Başlangıç Noktası (main.ts)

import { bootstrapApplication } from '@angular/platform-browser';

import { AppComponent } from './app.component';

import { provideRouter } from '@angular/router';

import { provideHttpClient } from '@angular/common/http';

import { routes } from './app.routes';

 

bootstrapApplication(AppComponent, {

  providers: [

    provideRouter(routes),       // Rota sistemini aktif eder

    provideHttpClient()          // HTTP sistemini aktif eder

  ]

}).catch(err => console.error(err));


7. Mimari Optimizasyon: Kod Bölme (Code Splitting) ve Ertelenebilir Görünümler (Deferrable Views)

Angular web sitelerinin açılış hızını maksimuma çıkarmak için projedeki tüm kodları tek bir devasa dosya yerine küçük parçalar halinde derler. Rota geçişlerinde kullanılan loadComponent yapısı sayesinde ilgili sayfanın kodu sadece kullanıcı o sayfaya tıkladığında indirilir. [8, 13, 14, 15]

Ayrıca şablon tasarımlarında @defer blokları kullanılarak, sayfanın alt kısımlarında kalan veya ağır yük getiren grafik/harita gibi bileşenlerin yüklenmesi, kullanıcının ekranı kaydırıp o bölgeye gelmesine (viewport) kadar ertelenebilir.

Uygulama Örneği: Ağır Bir Yükü Ertelenmiş Yükleme İle Getirme

HTML Şablon Dosyası (rapor.component.html)

<div class="ust-alan">

  <h1>Yönetim Paneli Raporları</h1>

  <p>Bu alan hemen yüklenir ve etkileşime hazır olur.</p>

</div>

 

<!-- Kullanıcı ekranı kaydırıp bu alana yaklaştığında (on viewport) bileşen yüklenir -->

@defer (on viewport) {

  <app-agir-grafik-bileseni></app-agir-grafik-bileseni>

} @loading {

  <p>Grafik yükleniyor, lütfen bekleyin...</p>

} @placeholder {

  <div class="bos-alan">Grafiği görmek için aşağı kaydırın.</div>

} @error {

  <p>Grafik yüklenirken bir ağ hatası oluştu.</p>

}


8. Test Stratejileri: Birim Testleri (Unit Testing)

Yazdığımız kodların iş kurallarına tam uyup uymadığını otomatik olarak denetlemek için birim testleri yazarız. Angular, test ortamı için hazır şablon araçları barındırır. TestBed nesnesi kullanılarak sanal bir ortamda bağımsız bileşenimiz ayağa kaldırılır, tıklama simülasyonları yapılır ve sinyallerin çıktısı doğrulanır.

Uygulama Örneği: Sinyal Tabanlı Sayacın Test Edilmesi

Test Edilecek Bileşen Kodu (sayac.component.ts)

import { Component, signal } from '@angular/core';

 

@Component({

  selector: 'app-sayac',

  standalone: true,

  template: `<button (click)="artir()">{{ deger() }}</button>`

})

export class SayacComponent {

  deger = signal(0);

  artir() {

    this.deger.update(n => n + 1);

  }

}

Test Senaryo Dosyası (sayac.component.spec.ts)

import { TestBed, ComponentFixture } from '@angular/core/testing';

import { SayacComponent } from './sayac.component';

 

describe('SayacComponent', () => {

  let component: SayacComponent;

  let fixture: ComponentFixture<SayacComponent>;

 

  beforeEach(async () => {

    await TestBed.configureTestingModule({

      imports: [SayacComponent] // Bağımsız bileşeni test modülüne ekler

    }).compileComponents();

 

    fixture = TestBed.createComponent(SayacComponent);

    component = fixture.componentInstance;

    fixture.detectChanges(); // Değişiklikleri şablona yansıtır

  });

 

  it('Başlangıç değeri sıfır olmalıdır', () => {

    expect(component.deger()).toBe(0);

  });

 

  it('Butona tıklandığında sinyal değeri 1 artmalıdır', () => {

    // Buton elementini bulup tıklama simülasyonu yaparız

    const buttonElement: HTMLButtonElement = fixture.nativeElement.querySelector('button');

    buttonElement.click();

   

    // Sinyal değerinin değiştiğini doğrularız

    expect(component.deger()).toBe(1);

  });

});

 

 

 

1. Eski Sürüm Yapıları: Modül Tabanlı Mimari (Angular < 16)

Modern Angular projelerinde her bileşen kendi bağımlılığını yönetirken, eski sürümlerde her yapının bir Modül (NgModule) çatısı altında toplanması zorunluydu. Uygulamanın çalışabilmesi için en az bir ana modül (AppModule) bulunmalı ve bileşenler, direktifler ya da boru hatları bu modüle kayıt edilmeliydi.

+-------------------------------------------------------+

 

|                    AppModule                          |

|                                                       |

|  [declarations] --> Bileşen, Direktif, Pipe Kaydı     |

|  [imports]      --> Diğer Yardımcı Modüller (Common)  |

|  [providers]    --> Servis ve Veri Sağlayıcıları      |

|  [bootstrap]    --> Ana Başlangıç Bileşeni             |

+-------------------------------------------------------+

                           |

            +--------------+--------------+

 

            |                             |

    [TarifBileseni]               [ListeBileseni]

Uygulama Örneği: Modül Tabanlı Tarif ve Alışveriş Listesi Uygulaması

Eski nesil mimariyi anlamak için bir tarif bileşeni ve bunu tarayıcıya tanıtan modül dosyasını kurgulayalım.

Modül Dosyası (app.module.ts)

import { NgModule } from '@angular/core';

import { BrowserModule } from '@angular/platform-browser';

import { FormsModule } from '@angular/forms';

 

import { AppComponent } from './app.component';

import { TarifBileseni } from './tarif/tarif.component';

import { DropdownDirektif } from './shared/dropdown.directive';

 

@NgModule({

  declarations: [

    AppComponent,

    TarifBileseni,      // Modüle bağlı bileşeni buraya kaydediyoruz

    DropdownDirektif    // Özel direktif modüldeki tüm bileşenlerin kullanımına açılır

  ],

  imports: [

    BrowserModule,      // Tarayıcı özellikleri (ngIf, ngFor vb. için)

    FormsModule         // İki yönlü veri bağlama desteği (ngModel)

  ],

  providers: [],        // Eski nesil servis sağlayıcıları alanı

  bootstrap: [AppComponent] // Uygulamanın ilk çalıştıracağı bileşen

})

export class AppModule { }

Bileşen Dosyası (tarif.component.ts)

import { Component } from '@angular/core';

 

@Component({

  selector: 'app-tarif',

  template: `

    <div class="tarif-kart" appDropdown>

      <h3>{{ tarifAdi }}</h3>

      <ul>

        <li *ngFor="let malzeme of malzemeler">{{ malzeme }}</li>

      </ul>

    </div>

  `

  // standalone: true ifadesi ESKİ yapılarda bulunmaz!

})

export class TarifBileseni {

  tarifAdi: string = 'Mercimek Çorbası';

  malzemeler: string[] = ['Mercimek', 'Soğan', 'Havuç', 'Zeytinyağı'];

}


2. NgRx Merkezi Durum Yönetimi (State Management) Mimarisi

Büyük ölçekli projelerde, bileşenlerin birbirine sürekli veri göndermesi (Input/Output zincirleri) kodun karmaşıklaşmasına neden olur. NgRx, veriyi tek bir merkezi depoda (Store) toplar. Bileşenler bu depodan veri okur veya depodaki veriyi değiştirmek için emir (Action) yayınlar.

+------------------------------------------------------------+

 

|                       NgRx Döngüsü                         |

+------------------------------------------------------------+

       |                                              ^

       v                                              |

 [Bileşen (Component)]                         [Seçici (Selector)]

 

       |                                              |

       v (Emir Yayınlar)                              |

   [Aksiyon (Action)]                                 |

 

       |                                              |

       v                                              |

  [Yönetici (Reducer)] ----> [Merkezi Depo (Store)] --+

Uygulama Örneği: NgRx ile Kurs Sepeti Yönetimi

1. Aksiyonların Tanımlanması (sepet.actions.ts)

import { createAction, props } from '@ngrx/store';

 

export const kursEkle = createAction(

  '[Kurs Sayfası] Kurs Ekle',

  props<{ kursAdi: string }>()

);

 

export const sepetiTemizle = createAction('[Kurs Sayfası] Sepeti Temizle');

2. Depo Yönetici Fonksiyonu (sepet.reducer.ts)

import { createReducer, on } from '@ngrx/store';

import * as SepetAksiyonlari from './sepet.actions';

 

export interface SepetEyaleti {

  secilenKurslar: string[];

}

 

export const ilkDurum: SepetEyaleti = {

  secilenKurslar: []

};

 

export const sepetReducer = createReducer(

  ilkDurum,

  // Kurs ekleme emri geldiğinde yeni durumu üretir

  on(SepetAksiyonlari.kursEkle, (mevcutDurum, { kursAdi }) => ({

    ...mevcutDurum,

    secilenKurslar: [...mevcutDurum.secilenKurslar, kursAdi]

  })),

  // Sepeti temizleme emri geldiğinde diziyi boşaltır

  on(SepetAksiyonlari.sepetiTemizle, () => ({

    secilenKurslar: []

  }))

);

3. Bileşen İçinde Kullanımı (kurs-listesi.component.ts)

import { Component, inject } from '@angular/core';

import { Store } from '@ngrx/store';

import { Observable } from 'rxjs';

import { kursEkle } from './sepet.actions';

import { CommonModule } from '@angular/common';

 

@Component({

  selector: 'app-kurs-listesi',

  standalone: true,

  imports: [CommonModule],

  template: `

    <h3>Mevcut Kurslar</h3>

    <button (click)="sepeteEkle('Angular - The Complete Guide')">Angular Kursunu Ekle</button>

   

    <hr>

    <h4>Sepetteki Kurs Sayısı: {{ (sepetKurslari$ | async)?.length }}</h4>

  `

})

export class KursListesiComponent {

  private store = inject(Store<{ sepet: { secilenKurslar: string[] } }>);

 

  // Depodaki veriyi canlı olarak dinleyen akış (Observable)

  sepetKurslari$: Observable<string[]> = this.store.select(state => state.sepet.secilenKurslar);

 

  sepeteEkle(isim: string) {

    // Depoya emir gönderiliyor

    this.store.dispatch(kursEkle({ kursAdi: isim }));

  }

}


3. Yeni Nesil Bağımsız Mimari Üzerinden Kapsamlı Uygulama Pratikleri

Angular’ın en güncel standartlarını kullanarak; Sinyaller, Dinamik Bağımsız Bileşenler ve Yeni Kontrol Akışları (@if, @for) içeren iki farklı mini proje inşa edelim.

Pratik 1: Dinamik Bildirim Paneli (Notification Center)

Bu uygulamada, kullanıcının ekrandan butonlara basarak dinamik uyarı kartları (başarılı, hata, uyarı) oluşturmasını ve bu kartların sinyaller üzerinden anlık olarak ekrandan silinmesini sağlayacağız.

Bildirim Servisi (bildirim.service.ts)

import { Injectable, signal } from '@angular/core';

 

export interface Bildirim {

  id: number;

  mesaj: string;

  tip: 'success' | 'danger' | 'warning';

}

 

@Injectable({

  providedIn: 'root'

})

export class BildirimService {

  // Tüm bildiriler sinyal dizisinde tutuluyor

  bildirimler = signal<Bildirim[]>([]);

  private sayac = 0;

 

  bildirimEkle(mesaj: string, tip: 'success' | 'danger' | 'warning') {

    const yeni: Bildirim = { id: ++this.sayac, mesaj, tip };

    // Mevcut dizinin üzerine yeni bildirimi ekleyerek sinyali güncelliyoruz

    this.bildirimler.update(liste => [...liste, yeni]);

 

    // 4 saniye sonra bildirimi otomatik siler

    setTimeout(() => this.bildirimSil(yeni.id), 4000);

  }

 

  bildirimSil(id: number) {

    this.bildirimler.update(liste => liste.filter(b => b.id !== id));

  }

}

Bildirim Ekranı Bileşeni (bildirim-merkezi.component.ts)

import { Component, inject } from '@angular/core';

import { CommonModule } from '@angular/common';

import { BildirimService } from './bildirim.service';

 

@Component({

  selector: 'app-bildirim-merkezi',

  standalone: true,

  imports: [CommonModule],

  template: `

    <div class="yonetim">

      <button (click)="tetikle('İşlem Başarılı!', 'success')">Başarı Ekle</button>

      <button (click)="tetikle('Sistem Hatası!', 'danger')">Hata Ekle</button>

    </div>

 

    <div class="bildirim-kutusu">

      <!-- Yeni nesil şablon döngüsü -->

      @for (b of servis.bildirimler(); track b.id) {

        <div [ngClass]="['alarm', b.tip]">

          <span>{{ b.mesaj }}</span>

          <button (click)="servis.bildirimSil(b.id)">x</button>

        </div>

      }

    </div>

  `,

  styles: [`

    .alarm { padding: 10px; margin: 5px; border-radius: 4px; display: flex; justify-content: space-between; }

    .success { background-color: #d4edda; color: #155724; }

    .danger { background-color: #f8d7da; color: #721c24; }

  `]

})

export class BildirimMerkeziComponent {

  servis = inject(BildirimService);

 

  tetikle(mesaj: string, tip: 'success' | 'danger' | 'warning') {

    this.servis.bildirimEkle(mesaj, tip);

  }

}


Pratik 2: Gerçek Zamanlı Arama ve Filtreleme Kartı (Sinyal Tabanlı)

Kullanıcı arama kutusuna harf girdikçe, sinyal mimarisi sayesinde sunucuya gereksiz istek atmadan, hafızadaki verileri saniyeler içinde filtreleyen bir akıllı arama motoru geliştirelim.

Arama Bileşeni (arama-motoru.component.ts)

import { Component, signal, computed } from '@angular/core';

import { FormsModule } from '@angular/forms';

 

interface Eleman {

  id: number;

  baslik: string;

  kategori: string;

}

 

@Component({

  selector: 'app-arama-motoru',

  standalone: true,

  imports: [FormsModule],

  template: `

    <div class="arama-alani">

      <input

        [(ngModel)]="aramaMetni"

        placeholder="Kurs veya konu arayın..."

        class="arama-girdisi"

      >

    </div>

 

    <div class="sonuclar">

      <h4>Bulunan Sonuçlar ({{ filtrelenmişElemanlar().length }})</h4>

     

      <ul>

        @for (item of filtrelenmişElemanlar(); track item.id) {

          <li>

            <strong>{{ item.baslik }}</strong> - <small>{{ item.kategori }}</small>

          </li>

        } @empty {

          <p>Kriterlere uygun kurs bulunamadı.</p>

        }

      </ul>

    </div>

  `

})

export class AramaMotoruComponent {

  // Kullanıcının yazdığı metni tutan ham sinyal

  aramaMetni = signal<string>('');

 

  // Veritabanından gelmiş gibi davranan sabit veri listesi sinyali

  tumVeriler = signal<Eleman[]>([]);

 

  // Computed Sinyal: aramaMetni her değiştiğinde otomatik olarak listeyi süzebilir

  filtrelenmişElemanlar = computed(() => {

    const aranan = this.aramaMetni().toLowerCase().trim();

   

    if (!aranan) {

      return this.tumVeriler();

    }

   

    return this.tumVeriler().filter(item =>

      item.baslik.toLowerCase().includes(aranan) ||

      item.kategori.toLowerCase().includes(aranan)

    );

  });

 

  constructor() {

    // Sayfa açıldığında sahte verileri yüklüyoruz

    this.tumVeriler.set([

      { id: 1, baslik: 'Angular Geliştirici Kılavuzu', kategori: 'Frontend' },

      { id: 2, baslik: 'RxJS ile Asenkron Programlama', kategori: 'Mimariler' },

      { id: 3, baslik: 'TypeScript Tip Güvenliği Temelleri', kategori: 'Programlama' },

      { id: 4, baslik: 'NgRx ile State Yönetimi', kategori: 'Frontend' }

    ]);

  }

}