Mert Özen Her Satırda Daha İleri
Frontend Angular — #03

Angular'da İlk Component: Decorator, Selector ve Template Anatomisi

Mert Özen 31 Eki 2026 6 dk 1 görüntülenme
Angular'da İlk Component: Decorator, Selector ve Template Anatomisi

Angular component'inin anatomisini söküyoruz: @Component decorator'ı, selector, template ve stiller. CLI ile component üretip component ağacını ve style encapsulation'ı görüyoruz.

Sürüm notu: Bu yazıdaki kod ve komutlar Angular 12 içindir.

Ekrandaki Her Şey Bir Component

Bir web sayfasına Angular gözlüğüyle baktığında artık tek parça bir HTML görmezsin. Üstteki menü bir component, sol taraftaki kategori listesi bir component, ortadaki her ürün kartı da ayrı bir component. Hepsi LEGO parçaları gibi birbirine takılır ve sayfa dediğimiz şey, bu parçaların bir araya gelmiş hâlidir.

Daha önce oluşturduğumuz projede ekranda gördüğün hoş geldin sayfası da aslında tek bir component'ti: AppComponent. Bu yazıda o component'in içini açacak, neyin nerede durduğunu görecek ve sonra kendi component'imizi sıfırdan üreteceğiz.

AppComponent'in İçine Bakalım

Projede src/app/app.component.ts dosyasını aç. Karşına şuna benzer bir kod çıkacak:

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'ilk-uygulama';
}

Üç parça var ve üçü de bir component'in olmazsa olmazı. En altta düz bir TypeScript class'ı duruyor: AppComponent. İçinde title adında tek bir property var. Bu class component'in beynidir; veriyi tutar, davranışı tanımlar.

Class'ın hemen üstündeki @Component({...}) satırı ise bir decorator. Decorator, bir class'a "sen sıradan bir class değilsin, bir component'sin" diyen etikettir. Tek başına AppComponent sadece bir TypeScript class'ıdır; Angular onu bu etiket sayesinde tanır ve içine verdiğimiz ayarlara göre ekrana yerleştirir.

En üstteki import satırı da Component decorator'ını Angular'ın çekirdek paketinden getiriyor. Kullanacağın her Angular parçasını bu şekilde içeri alırsın.

Decorator'ın İçindeki Üç Ayar

selector, component'in HTML'deki adıdır. 'app-root' yazdığımız için bu component'i bir template'te <app-root></app-root> etiketiyle çağırırız. Projedeki src/index.html dosyasını açarsan, body'nin içinde tam olarak bu etiketi görürsün. Angular uygulama açılırken o etiketi bulur ve yerine AppComponent'in içeriğini basar.

templateUrl, component'in görünüşünü tanımlayan HTML dosyasını gösterir. styleUrls ise o görünüşe ait CSS dosyalarının listesidir; dizi olmasının sebebi birden fazla stil dosyası verebilmen.

Bir restoran benzetmesiyle düşün: class mutfaktır, yemeği o hazırlar. Template servis tabağıdır, yemeğin nasıl sunulacağını belirler. Stil dosyası da tabağın süslemesidir. Selector ise menüdeki yemeğin adı; garsona o adı söylediğinde tabak masana gelir.

Template'te Veriyi Göstermek

Class'taki veriyi template'e taşımak için çift süslü parantez kullanırız. app.component.html dosyasının içeriğini silip şunu yaz:

<h1>{{ title }}</h1>
<p>Bu sayfa AppComponent tarafından çiziliyor.</p>

Kaydettiğinde ekranda ilk-uygulama yazısını göreceksin. {{ title }} ifadesi, class'taki title property'sinin değerini template'e basar. Class'ta değeri değiştirirsen ekran da değişir. Bu yönteme interpolation denir ve data binding'in en basit hâlidir. Data binding'in diğer türlerini ilerleyen yazılarda tek tek detaylandıracağız.

Kendi Component'imizi Üretelim

Elle dört dosya açıp hepsini birbirine bağlamak yerine Angular CLI'ye yaptırıyoruz. Proje klasöründeyken terminalde şunu çalıştır:

ng generate component product-card

Kısaltmasıyla ng g c product-card da aynı işi yapar. CLI çıktısı şuna benzer:

CREATE src/app/product-card/product-card.component.css (0 bytes)
CREATE src/app/product-card/product-card.component.html (27 bytes)
CREATE src/app/product-card/product-card.component.spec.ts (654 bytes)
CREATE src/app/product-card/product-card.component.ts (291 bytes)
UPDATE src/app/app.module.ts (497 bytes)

Dört dosya oluştu ve bir dosya güncellendi. .ts class ve decorator, .html template, .css stil, .spec.ts ise bu component'in test dosyası. Testleri ilerleyen yazılarda ele alacağız, şimdilik o dosyaya dokunmana gerek yok.

Asıl dikkat çekmesi gereken satır en sondaki UPDATE. CLI, yeni component'i app.module.ts içindeki declarations listesine kendisi ekledi. Angular 12'de her component bir module'e kayıtlı olmak zorundadır; kayıtlı olmayan bir component'i template'te kullanmaya çalışırsan "is not a known element" hatası alırsın. Module'lerin ne işe yaradığını bir sonraki yazıda detaylandıracağız.

Oluşan Component'i Okuyalım

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

@Component({
  selector: 'app-product-card',
  templateUrl: './product-card.component.html',
  styleUrls: ['./product-card.component.css']
})
export class ProductCardComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

}

Tanıdık bir iskelet. CLI selector'a otomatik olarak app- ön ekini koydu; bu ön ek, kendi component'lerini standart HTML etiketlerinden ve başka kütüphanelerin component'lerinden ayırmak için var. Class adı da Angular'ın isimlendirme kuralına göre ProductCardComponent oldu.

Fazladan iki şey görüyorsun: boş bir constructor ve ngOnInit metodu. ngOnInit, component ekrana hazırlanırken Angular'ın çağırdığı bir lifecycle hook. Constructor ile arasındaki fark önemli ama şimdilik ikisini de boş bırakabilirsin; lifecycle hook'ları ayrı bir yazıda inceleyeceğiz.

Şimdi component'e biraz içerik verelim. Class'a iki property ekle:

export class ProductCardComponent implements OnInit {
  productName = 'Mekanik Klavye';
  price = 1450;

  constructor() { }

  ngOnInit(): void {
  }
}

Template'i de şöyle doldur:

<div class="card">
  <h3>{{ productName }}</h3>
  <p>{{ price }} TL</p>
</div>

Component'i Kullanmak: Component Ağacı

Component hazır ama henüz kimse onu çağırmıyor. app.component.html dosyasına dön ve selector'ı bir HTML etiketi gibi yaz:

<h1>{{ title }}</h1>
<app-product-card></app-product-card>
<app-product-card></app-product-card>

Ekranda iki ürün kartı belirecek. Aynı component'i istediğin kadar kullanabilirsin; her kullanım kendi bağımsız kopyasıdır. Bir kartın verisini değiştirmek diğerini etkilemez.

Burada aslında bir ağaç kurduk. En tepede AppComponent var, onun altında iki ProductCardComponent. Gerçek bir uygulamada bu ağaç dallanır budaklanır: sayfa component'i, onun içinde liste component'i, listenin içinde kart component'leri. Angular uygulamasını anlamanın en iyi yolu, onu bu ağacın kendisi olarak düşünmektir.

İki kartın da aynı ürünü göstermesi şu an biraz garip duruyor. Parent component'ten child component'e veri göndermenin yolu var ve onu component iletişimi konusunda detaylandıracağız.

Stiller Neden Birbirine Karışmıyor?

product-card.component.css dosyasına şunu yaz:

h3 {
  color: crimson;
}

Kartlardaki başlıklar kırmızı oldu ama AppComponent'teki h1 ya da sayfadaki başka hiçbir h3 etkilenmedi. Normal CSS'te h3 seçicisi sayfadaki bütün h3'leri yakalardı. Angular ise her component'in stilini o component'e hapseder.

Tarayıcının geliştirici araçlarıyla bir karta bakarsan, elemanların üzerinde _ngcontent-xyz-c12 gibi garip attribute'lar görürsün. Angular derleme sırasında her component'in elemanlarına benzersiz bir attribute ekler ve CSS seçicilerini de bu attribute'a bağlar. Bu davranışın adı view encapsulation, varsayılan modu da ViewEncapsulation.Emulated. Her component'in kendi odası var gibi düşün: odanın duvarını boyarsın, koridor etkilenmez.

Bütün uygulamayı ilgilendiren stiller içinse projenin kökündeki src/styles.css dosyası var. Font, renk paleti, sıfırlama kuralları gibi global şeyler oraya yazılır.

Template ve Stil Dosyasız Component

Çok küçük component'ler için ayrı HTML ve CSS dosyası açmak gereksiz gelebilir. Decorator'da templateUrl yerine template, styleUrls yerine styles kullanarak her şeyi tek dosyada yazabilirsin:

@Component({
  selector: 'app-badge',
  template: `<span class="badge">Yeni</span>`,
  styles: [`.badge { background: gold; padding: 2px 8px; }`]
})
export class BadgeComponent { }

Ters tırnak (backtick) kullandığımız için template'i birden fazla satıra da yayabilirsin. Kural basit: birkaç satırı geçmeyen template'ler inline kalabilir, gerisi ayrı dosyaya. Template şiştikçe TypeScript dosyasının içinde HTML okumak hızla yorucu hâle gelir.

CLI'ye en baştan inline component ürettirmek istersen ng g c badge --inline-template --inline-style komutunu kullanabilirsin.

Küçük Bir Deneme

Şimdi sıra sende. CLI ile user-profile adında yeni bir component üret. Class'ına name, role ve city property'lerini ekle, template'te bu üçünü bir kart içinde göster. Ardından component'i AppComponent'in template'ine üç kez yerleştir.

Sonra iki küçük şeyi bilerek boz. Önce app.module.ts dosyasını aç, declarations listesinden UserProfileComponent satırını sil ve terminaldeki hatayı oku. Satırı geri koyduktan sonra bu kez component'in stil dosyasına bir p { color: teal; } kuralı yaz ve AppComponent'teki paragrafların etkilenip etkilenmediğine bak.

O declarations listesi neden bu kadar önemli, bir module tam olarak neyi kim için tanımlar? Bir sonraki yazıda Angular 12 uygulamasının iskeleti olan NgModule'ü masaya yatıracağız.