Bir bileşen, alt öğeleri bulan ve enjektörlerinden değerleri okuyan sorgular tanımlayabilir.
Geliştiriciler sorguları en çok alt bileşenlere, yönergelere, DOM öğelerine ve daha fazlasına referans almak için kullanır.
İki sorgu kategorisi vardır: görünüm sorguları ve içerik sorguları.
Görünüm Sorguları #
Görünüm sorguları, bileşenin görünümündeki öğelerden (bileşenin kendi şablonunda tanımlanan öğeler) sonuçları alır. Tek bir sonuç için @ViewChild dekoratörü ile sorgulama yapabilirsiniz.
@Component({
selector: 'custom-card-header',
...
})
export class CustomCardHeader {
text: string;
}
@Component({
selector: 'custom-card',
template: '<custom-card-header>Visit sunny California!</custom-card-header>',
})
export class CustomCard {
@ViewChild(CustomCardHeader) header: CustomCardHeader;
ngAfterViewInit() {
console.log(this.header.text);
}
}
Bu örnekte, CustomCard bileşeni bir alt CustomCardHeader sorgular ve ngAfterViewInit içinde sonuca erişir.
Sorgu bir sonuç bulamazsa, değeri tanımsız olur. Hedef öğe NgIf tarafından gizlenmişse bu durum oluşabilir. Angular, uygulama durumunuz değiştikçe @ViewChild sonucunu güncel tutar.
Görünüm sorgusu sonuçları ngAfterViewInit yaşam döngüsü yönteminde kullanılabilir hale gelir. Bu noktadan önce değer tanımsızdır. Bileşen yaşam döngüsü hakkında ayrıntılar için Lifecycle bölümüne bakın.
Ayrıca @ViewChildren dekoratörü ile birden fazla sonuç için sorgulama yapabilirsiniz.
@Component({
selector: 'custom-card-action',
...,
})
export class CustomCardAction {
text: string;
}
@Component({
selector: 'custom-card',
template: `
<custom-card-action>Save</custom-card-action>
<custom-card-action>Cancel</custom-card-action>
`,
})
export class CustomCard {
@ViewChildren(CustomCardAction) actions: QueryList<CustomCardAction>;
ngAfterViewInit() {
this.actions.forEach(action => {
console.log(action.text);
});
}
}
@ViewChildren, sorgu sonuçlarını içeren bir QueryList nesnesi oluşturur. Sorgu sonuçlarında zaman içinde yapılan değişikliklere changes özelliği aracılığıyla abone olabilirsiniz.
Sorgular asla bileşen sınırlarını delip geçmez. Görünüm sorguları yalnızca bileşenin şablonundan sonuç alabilir.
İçerik sorguları #
İçerik sorguları, bileşenin içeriğindeki öğelerden (kullanıldığı şablonda bileşenin içine yerleştirilmiş öğeler) sonuçları alır. Tek bir sonuç için @ContentChild dekoratörü ile sorgulama yapabilirsiniz.
@Component({
selector: 'custom-toggle',
...
})
export class CustomToggle {
text: string;
}
@Component({
selector: 'custom-expando',
...
})
export class CustomExpando {
@ContentChild(CustomToggle) toggle: CustomToggle;
ngAfterContentInit() {
console.log(this.toggle.text);
}
}
@Component({
selector: 'user-profile',
template: `
<custom-expando>
<custom-toggle>Show</custom-toggle>
</custom-expando>
`
})
Bu örnekte, CustomExpando bileşeni bir alt CustomToggle için sorgulama yapar ve sonuca ngAfterContentInit içinde erişir.
Sorgu bir sonuç bulamazsa, değeri tanımsız olur. Bu, hedef öğe yoksa veya NgIf tarafından gizlenmişse oluşabilir. Angular, uygulama durumunuz değiştikçe @ContentChild sonucunu güncel tutar.
Varsayılan olarak, içerik sorguları yalnızca bileşenin doğrudan alt öğelerini bulur ve alt öğelere geçmez.
İçerik sorgusu sonuçları ngAfterContentInit yaşam döngüsü yönteminde kullanılabilir hale gelir. Bu noktadan önce değer tanımsızdır. Bileşen yaşam döngüsü hakkında ayrıntılar için Lifecyclebölümüne bakın.
Ayrıca @ContentChildren dekoratörü ile birden fazla sonuç için sorgulama yapabilirsiniz.
@Component({
selector: 'custom-menu-item',
...
})
export class CustomMenuItem {
text: string;
}
@Component({
selector: 'custom-menu',
...,
})
export class CustomMenu {
@ContentChildren(CustomMenuItem) items: QueryList<CustomMenuItem>;
ngAfterContentInit() {
this.items.forEach(item => {
console.log(item.text);
});
}
}
@Component({
selector: 'user-profile',
template: `
<custom-menu>
<custom-menu-item>Cheese</custom-menu-item>
<custom-menu-item>Tomato</custom-menu-item>
</custom-menu>
`
})
@ContentChildren, sorgu sonuçlarını içeren bir QueryList nesnesi oluşturur. Sorgu sonuçlarında zaman içinde yapılan değişikliklere changes özelliği aracılığıyla abone olabilirsiniz.
Sorgular asla bileşen sınırlarından geçmez. İçerik sorguları yalnızca bileşenin kendisiyle aynı şablondaki sonuçları alabilir.
Sorgu konumlandırıcıları #
Her sorgu dekoratörü için bu ilk parametre onun yer belirleyicisidir.
Çoğu zaman, konumlandırıcınız olarak bir bileşen veya yönerge kullanmak istersiniz.
Alternatif olarak bir template reference variable karşılık gelen bir dize konumlandırıcı belirtebilirsiniz.
@Component({
...,
template: `
<button #save>Save</button>
<button #cancel>Cancel</button>
`
})
export class ActionBar {
@ViewChild('save') saveButton: ElementRef<HTMLButtonElement>;
}
Birden fazla öğe aynı şablon referans değişkenini tanımlarsa, sorgu ilk eşleşen öğeyi alır.
Angular, CSS seçicilerini sorgu konumlandırıcıları olarak desteklemez.
Sorgular ve enjektör ağacı #
Daha gelişmiş durumlar için, herhangi bir ProviderToken‘ı konum belirleyici olarak kullanabilirsiniz. Bu, bileşen ve yönerge sağlayıcılarına dayalı olarak öğeleri bulmanızı sağlar.
const SUB_ITEM = new InjectionToken<string>('sub-item');
@Component({
...,
providers: [{provide: SUB_ITEM, useValue: 'special-item'}],
})
export class SpecialItem { }
@Component({...})
export class CustomList {
@ContentChild(SUB_ITEM) subItemType: string;
}
Yukarıdaki örnekte konum belirleyici olarak bir InjectionToken kullanılmıştır, ancak belirli öğeleri bulmak için herhangi bir ProviderToken kullanabilirsiniz.
Sorgu seçenekleri #
Tüm sorgu dekoratörleri ikinci parametre olarak bir options nesnesi kabul eder. Bu seçenekler, sorgunun sonuçlarını nasıl bulacağını kontrol eder.
Statik sorgular #
@ViewChild ve @ContentChild sorguları static seçeneğini kabul eder.
@Component({
selector: 'custom-card',
template: '<custom-card-header>Visit sunny California!</custom-card-header>',
})
export class CustomCard {
@ViewChild(CustomCardHeader, {static: true}) header: CustomCardHeader;
ngOnInit() {
console.log(this.header.text);
}
}
static: true ayarını yaparak, Angular’a bu sorgunun hedefinin her zaman mevcut olduğunu ve koşullu olarak işlenmediğini garanti edersiniz. Bu, sonucu ngOnInit yaşam döngüsü yönteminde daha erken kullanılabilir hale getirir.
Statik sorgu sonuçları başlatma işleminden sonra güncellenmez.
Static seçeneği @ViewChildren ve @ContentChildren sorguları için kullanılamaz.
İçerik soyundan gelenler #
Varsayılan olarak, içerik sorguları yalnızca bileşenin doğrudan alt öğelerini bulur ve alt öğelere geçmez.
@Component({
selector: 'custom-expando',
...
})
export class CustomExpando {
@ContentChild(CustomToggle) toggle: CustomToggle;
}
@Component({
selector: 'user-profile',
template: `
<custom-expando>
<some-other-component>
<!-- custom-toggle will not be found! -->
<custom-toggle>Show</custom-toggle>
</some-other-component>
</custom-expando>
`
})
Yukarıdaki örnekte, CustomExpando <custom-toggle> öğesini bulamaz çünkü öğesinin doğrudan bir alt öğesi değildir. descendants: true ayarını yaparak, sorguyu aynı şablondaki tüm alt öğeleri dolaşacak şekilde yapılandırırsınız. Ancak sorgular, diğer şablonlardaki öğeleri geçmek için asla bileşenlere girmez.
Görünüm sorgularında bu seçenek bulunmamaktadır çünkü her zaman alt öğelere doğru ilerlerler.
Bir elemanın enjektöründen belirli değerleri okuma #
Varsayılan olarak, sorgu konumlandırıcısı hem aradığınız öğeyi hem de alınan değeri belirtir. Alternatif olarak, yer belirleyici tarafından eşleştirilen öğeden farklı bir değer almak için read seçeneğini belirtebilirsiniz.
@Component({...})
export class CustomExpando {
@ContentChild(ExpandoContent, {read: TemplateRef}) toggle: TemplateRef;
}
Yukarıdaki örnek, ExpandoContent yönergesine sahip bir öğeyi bulur ve bu öğeyle ilişkili TemplateRef‘i alır.
Geliştiriciler en yaygın olarak ElementRef ve TemplateRef‘i almak için read‘i kullanır.
QueryList Kullanımı #
@ViewChildren ve @ContentChildren öğelerinin her ikisi de bir sonuç listesi içeren bir QueryList nesnesi sağlar.
QueryList, sonuçlarla dizi benzeri bir şekilde çalışmak için map, reduce ve forEach gibi bir dizi kolaylık API’si sunar. toArray öğesini çağırarak geçerli sonuçların bir dizisini alabilirsiniz.
Sonuçlar her değiştiğinde bir şeyler yapmak için changes özelliğine abone olabilirsiniz.
Yaygın sorgu tuzakları #
Sorguları kullanırken, yaygın tuzaklar kodunuzun anlaşılmasını ve bakımını zorlaştırabilir.
Birden fazla bileşen arasında paylaşılan durum için her zaman tek bir doğruluk kaynağı bulundurun. Bu, farklı bileşenlerde tekrarlanan durumun senkronize olmadığı senaryoları önler.
Durumu doğrudan alt bileşenlere yazmaktan kaçının. Bu kalıp, anlaşılması zor ve ExpressionChangedAfterItHasBeenChecked hatalarına eğilimli kırılgan kodlara yol açabilir.
Durumu asla doğrudan üst veya ata bileşenlere yazmayın. Bu kalıp, anlaşılması zor ve ExpressionChangedAfterItHasBeenChecked hatalarına eğilimli kırılgan kodlara yol açabilir.