Table of contents
Merhaba,
Bu yazımda Angular da işimize yarayacak decorator kullanımından bahsedeceğim. Bu kullanımı anlatabilmek için bir component oluşturalım ve bu componentin input olarak aldığı parametrelerin zorunlu olması durumunu kontrol edelim.
Component oluşturma
İlk olarak projemizde aşağıdaki komut ile greeter componentimizi oluşturalım.
ng g c greeter
Component hazır olduğuna göre özelleştirme işlemini yapalım ve bu componentimiz basit olarak verilen bir isim için karşılama mesajı versin. Gerekli düzenlemeleri aşağıdaki gibi yapalım.
greeter.component.html içeriği
<h2>Hello, {{ name }}</h2>
<h3>{{ message }}</h3>
greeter.component.ts içeriği
import { Component, Input, VERSION } from '@angular/core';
@Component({
selector: 'app-greeter',
templateUrl: './greeter.component.html',
styleUrls: ['./greeter.component.css'],
})
export class GreeterComponent {
@Input() public name: string;
@Input() public message: string;
}
Görüldüğü gibi basit bir component. Şimdi name ve message değerlerini zorunlu yapmak istediğimizde iki seçenek kullanabiliriz. Birincisi selector tanımında bunu belirtmek ya da bir decorator yardımı ile bunu belirtmek. Bu konumuzun özelinde decorator oluşturalım ve onu kullanalım, ayrıca selector tanımında belirttiğimiz zorunluluğun bizim için çok işlevsel olmadığınıda görelim.
Decorator oluşturma
Decorator oluşturmak için projemizde bir decorators isim klasör açıp içerisinde de required.decorator.ts isimli bir dosya açıp fonksiyonumuzu yazalım.
required.decorator.ts içeriği
export function Required(target: object, propertyKey: string) {
Object.defineProperty(target, propertyKey, {
get() {
throw new Error(`Attribute '${propertyKey}' is required.`);
},
set(value) {
Object.defineProperty(target, propertyKey, {
value,
writable: true,
configurable: true,
});
},
configurable: true,
});
}
Şimdi yeni hazırladığımız bu require decorator tanımımızı componentimizde kullanalım. Gerekli düzenleme sonrası içeriğimiz aşağıdaki gibi olacaktır.
greeter.component.ts içeriği @Required kullanımı ile
import { Component, Input, VERSION } from '@angular/core';
import { Required } from '../decorators/required.decorator';
@Component({
selector: 'app-greeter',
templateUrl: './greeter.component.html',
styleUrls: ['./greeter.component.css'],
})
export class GreeterComponent {
@Input() @Required public name: string;
@Input() public message: string;
}
Bu düzenlemeden sonra yeni componentimizi kullanalım ve bize sağladığını zorunluluk kontrolünün sonucunu görelim. Bunun için app.component.html içerisinde aşağıdaki düzenlemeyi yapalım.
<h1>{{ title }}</h1>
<hr />
<app-greeter name="Samet" message="Custom decorator"></app-greeter>
Bu kullanım sonucu herhangi bir hata bulunmuyor ve ekran çıktımız aşağıdaki gibi oluyor.
Artık sıra zorunlu olarak belirtiğimiz alana değer vermeden kullanmaya geldi ve hazırlamış olduğumuz decorator tarafından da uyarı mesajımızı göreceğiz. Kodumuzu aşağıdaki gibi düzeltelim ve hatamızı görelim.
<h1>{{ title }}</h1>
<hr />
<app-greeter message="Custom decorator"></app-greeter>
Hata mesajında da görüldüğü gibi bu tarz bir decorator ile istediğimiz gibi özelleştirme yapabiliyoruz. Şimdi de decorator olmadan selector tanımında bir zorunluluk kontrolü yapalım ve onun sonucunu görelim. Bu işlem için kodumuzu aşağıdaki gibi değiştirelim sonra da kullanımına bakalım. Selector tanımında message bilgisini zorunlu olarak tanımladık
greeter.component.ts içeriği selector düzenleme kullanımı ile
import { Component, Input, VERSION } from '@angular/core';
import { Required } from '../decorators/required.decorator';
@Component({
selector: 'app-greeter[message]',
templateUrl: './greeter.component.html',
styleUrls: ['./greeter.component.css'],
})
export class GreeterComponent {
@Input() public name: string;
@Input() public message: string;
}
Son olarak kullanımımızda message bilgisini kullanmayalım ve sonuçlarını görelim.
<h1>{{ title }}</h1>
<hr />
<app-greeter name="Samet"></app-greeter>
Yukarıdaki gibi selector yardımı ile bir alanı zorunlu yaptığımızda aldığımız hata mesajında net olarak hangi alan için bu hatayı verdiğini bulmamız zor, ama bunun yerine kendi hazırlayacağımız custom decorator ile yukarıda yaptığımız required decoratoru gibi net olarak hangi alanda hata var bunu görebiliyoruz.
Ayrıca işlemlerimizi loglamak içinde bir decorator oluşturup onu kullanabiliriz.
log.decorator.ts içeriği
export function Log(params?: { color?: string }): MethodDecorator {
return function (target: Function, propertyKey: string, descriptor: any) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(
`%c |-> Entering '${propertyKey}' method`,
params ? `color:${params.color}` : ''
);
console.log(
`%c "${propertyKey}" method args:${args}`,
'background:green;color:white'
);
const result = originalMethod.apply(this, args);
console.log(
`%c <-| Leaving '${propertyKey}' method`,
params ? `color:${params.color}` : ''
);
return result;
};
return descriptor;
};
}
Yeni oluşturduğumuz be decorator ile istediğimiz method için log kaydı alabiliriz. Örnek kullanımı için app.component.ts içeriğine göz atalım.
app.component.ts içeriği
import { Component, OnInit, VERSION } from '@angular/core';
import { Log } from './decorators/log.decorator';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
public title = `Angular ${VERSION.major} Custom Decorator`;
@Log()
public ngOnInit(): void {
this.sayHi('Hi', 'Samet');
}
@Log({ color: 'red' })
public sayHi(message: string, name: string): void {
console.log(message, name);
}
}
Bu kullanım sonrası çıktımız aşağıdaki gibi olacaktır.
Sizde kendi ihtiyaçlarınıza göre bu tarz decorator yazıp işinizi kolaylaştırabilirsiniz. Konuya ait GitHub ve StackBlitz aşağıdadır.