Angular – Gelişmiş Component Yapılanması | ng-template
Merhaba,
Bu içeriğimizde Angular mimarisinde tasarımsal açıdan şablonlarla dinamik çalışmalar gerçekleştirmemizi sağlayan ng-template özelliğini inceliyor olacağız.
ng-template Nedir?
ng-template, ng-container gibi sayfa üzerinde HTML elementleriyle uğraşmaksızın bir bölüm/alan oluşturmamıza olanak sağlayan ve Document Object Model(DOM) içerisinde tanımlanmayan bir özelliktir. ng-container‘dan temel farkı, render edildiği taktirde dahi ayrı aparatlar aracılığıyla gösterilmediği sürece içerisindeki HTML elementlerin DOM üzerine işlenmemesidir.
Misal olarak aşağıdaki kod bloğunu incelerseniz eğer;
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<ng-container>
Container içerik
</ng-container>
<ng-template>
Template içerik
</ng-template>
`
})
export class AppComponent {
title = 'a';
}
Bu kod render edildiğinde ng-container‘ın çıktısının DOM’a eklendiğini lakin ng-template‘in çıktısının ise eklenmediğini göreceksiniz.
Buradan anlıyoruz ki, ng-template‘in nerede ve ne zaman görüntüleneceğini bildirmek bizim işimizdir.
ng-template‘i görüntülemek için aşağıdaki iki yöntemden birini kullanabilirsiniz:
ngTemplateOutletdirektifi- TemplateRef & ViewContainerRef öğeleri
ngTemplateOutlet Direktifi İle ng-template’i Görüntüleme
<ng-container *ngTemplateOutlet="templateIcerik">
Container içerik
</ng-container>
<ng-template #templateIcerik>
Template içerik
</ng-template>
Yukarıdaki kod bloğunu incelerseniz eğer ilgili ng-template‘e bir referans atıyoruz ve bu referansı ng-container üzerinde ‘ngTemplateOutlet’ direktifi eşliğinde çağırıyoruz. Yapılan render neticesine göz atarsanız eğer ng-template‘in ng-container içeriğini ezdiğini görüyoruz.
TemplateRef & ViewContainerRef İle ng-template’i Görüntüleme
‘TemplateRef’, ng-template‘i component üzerinde(.ts) temsil etmemizi sağlayan bir sınıfken, ‘ViewContainerRef’ ise ng-template‘in nerede oluşturulacağını belirtmemizi sağlayan başka bir sınıftır.
import { AfterViewInit, Component, TemplateRef, ViewChild, ViewContainerRef } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<ng-template #templateIcerik>
Template içerik
</ng-template>
`
})
export class AppComponent implements AfterViewInit {
constructor(private viewContainerRef: ViewContainerRef) {
}
@ViewChild("templateIcerik", { read: TemplateRef })
templateIcerik: TemplateRef<any>;
ngAfterViewInit(): void {
this.viewContainerRef.createEmbeddedView(this.templateIcerik);
}
}
Yukarıdaki kod bloğuna göz atarsanız eğer ng-template‘e yine bir referans verilmekte ve component’in .ts dosyası içerisinde ‘@ViewChild’ eşliğinde bu referans ‘TemplateRef’ türünde elde edilmektedir. Ardından dependency injection ile inject edilen ‘ViewContainerRef’ nesnesi üzerinden createEmbeddedView metodu kullanılarak ng-template sayfada görüntülenmektedir.
Evet, artık ng-template‘in ne olduğunu ve nasıl kullanıldığını öğrendiğimize göre gelin hangi durumlarda tercih edebileceğimizi inceleyelim.
ngIf İle ng-template Kullanımı
ngIf direktifini aşağıdaki gibi bir durumda birçok kez kullanmışsınızdır.
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<input [(ngModel)]="selected" type="checkbox"> Seç
<div *ngIf="selected">
Seçili
</div>
`
})
export class AppComponent {
selected: boolean = false;
}
Bu kodu yazmanın aşağıdaki gibi ng-template eşliğinde farklı bir yolu daha vardır.
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<input [(ngModel)]="selected" type="checkbox"> Seç
<ng-template [ngIf]="selected">
<div>
Seçili
</div>
</ng-template>
`
})
export class AppComponent {
selected: boolean = false;
}
Ya da aşağıdaki gibi if-else durumlarına göre şablon gösterimlerinde ng-template biçilmiş kaftandır.
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<div *ngIf="selected; then template1 else template2">
</div>
<ng-template #template1>
Şablon 1
</ng-template>
<ng-template #template2>
Şablon 2
</ng-template>
`
})
export class AppComponent {
selected: boolean = true;
}
Görüldüğü üzere şarta göre hangi ng-template‘in görüntüleneceğini if -> then -> else yapısı sayesinde belirlememizi sağlamaktadır. Ayrıca ilgili HTML elemanının yerine şarta uygun referansa karşılık gelen ng-template‘in içeriğini bastığına dikkatinizi çekerim.
Tabi yukarıdaki çalışmayı aşağıdaki gibi [ngIf], [ngIfThen] ve [ngIfElse] direktifleri eşliğinde de geliştirebiliriz.
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<ng-template [ngIf]="selected" [ngIfThen]="template1" [ngIfElse]="template2">
</ng-template>
<ng-template #template1>
Şablon 1
</ng-template>
<ng-template #template2>
Şablon 2
</ng-template>
`
})
export class AppComponent {
selected: boolean = true;
}
ngFor İle ng-template Kullanımı
Aşağıdaki ngFor direktifiyle olan çalışmayı ele alırsak eğer;
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<ul>
<li *ngFor="let product of products;trackBy: trackByProduct">
{{ product.name }}
</li>
</ul>
`
})
export class AppComponent {
products: { name: string, quantity: number }[] = [
{ name: "A Product", quantity: 15 },
{ name: "B Product", quantity: 25 },
{ name: "C Product", quantity: 35 },
{ name: "D Product", quantity: 45 }
]
trackByProduct(index, product: { name: string, quantity: number }) {
return product.name;
}
}
ng-template eşliğinde aşağıdaki gibi de inşa edebilirsiniz.
<ul>
<ng-template
ngFor let-product
[ngForOf]="products"
[ngForTrackBy]="trackByProduct">
<li>
{{ product.name }}
</li>
</ng-template>
</ul>
Burada görüldüğü üzere ngFor, [ngForOf] ve [ngForTrackBy] direktifleri bizlere eşlik etmektedir.
ngSwitch İle ng-template Kullanımı
ng-template‘i aynı şekilde ngSwitch ile birlikte de kullanabilmekteyiz. Şöyle ki;
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<input type="number" [(ngModel)]="number" max="5" min="1">
<div [ngSwitch]="number">
<div *ngSwitchCase="1">Bir</div>
<div *ngSwitchCase="2">İki</div>
<div *ngSwitchCase="3">Üç</div>
<div *ngSwitchCase="4">Dört</div>
<div *ngSwitchCase="5">Beş</div>
</div>
`
})
export class AppComponent {
number: number;
}
Yukarıdaki örneği ele alırsak render edildiğinde aşağıdaki gibi bir çalışma sergileyecektir.
Aynı operasyonu ng-template ile aşağıdaki gibi gerçekleştirirsek eğer aynı davranışı sergilemiş olacaktır.
<input type="number" [(ngModel)]="number" max="5" min="1">
<div [ngSwitch]="number">
<ng-template [ngSwitchCase]="1">
<div>Bir</div>
</ng-template>
<ng-template [ngSwitchCase]="2">
<div>İki</div>
</ng-template>
<ng-template [ngSwitchCase]="3">
<div>Üç</div>
</ng-template>
<ng-template [ngSwitchCase]="4">
<div>Dört</div>
</ng-template>
<ng-template [ngSwitchCase]="5">
<div>Beş</div>
</ng-template>
<ng-template ngSwitchDefault>
<div>Sıfır</div>
</ng-template>
</div>
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…
