Custom Structural Directive
Nima bu?
Structural directive DOM strukturasini o'zgartiradi. TemplateRef β ng-template ichidagi shablon havolasi; ViewContainerRef β shu joyga view (embedded view) yaratish/o'chirish konteyneri. createEmbeddedView() shablonni DOM'ga qo'shadi, clear() olib tashlaydi β *ngIf shu mexanizm asosida ishlaydi.
Kod misoli
import {
Directive,
Input,
TemplateRef,
ViewContainerRef,
inject,
} from '@angular/core';
@Directive({
selector: '[appUnless]',
standalone: true,
})
export class UnlessDirective {
private templateRef = inject(TemplateRef<unknown>);
private vcr = inject(ViewContainerRef);
private hasView = false;
@Input() set appUnless(condition: boolean) {
if (!condition && !this.hasView) {
this.vcr.createEmbeddedView(this.templateRef);
this.hasView = true;
} else if (condition && this.hasView) {
this.vcr.clear();
this.hasView = false;
}
}
}
<p *appUnless="isHidden">Shart false bo'lsa ko'rinadi (ngIf teskari)</p>
<ng-template [appUnless]="isHidden">
<p>Property binding usuli ham ishlaydi</p>
</ng-template>
@Component({
selector: 'app-unless-demo',
standalone: true,
imports: [UnlessDirective],
templateUrl: './unless-demo.component.html',
})
export class UnlessDemoComponent {
isHidden = false;
}
Muhim nuance: createEmbeddedView chaqirilganda yaratilgan view change detection daraxtida qoladi β vcr.clear() chaqirilmaguncha memory'da turadi, shuning uchun ngOnDestroy'da tozalash yoki hasView kabi flag bilan boshqarish shart (aks holda bir xil view bir necha marta yaratilib, xotira sΔ±zishi va DOM dublikati yuzaga keladi).
Imtihonda
- TemplateRef nima va qayerdan keladi?
- ViewContainerRef qayerga inject qilinadi?
- Embedded view vs component view farqi?
createEmbeddedViewni shart tekshirmasdan har o'zgarishda chaqirsak nima bo'ladi (dublikat view muammosi)?
Yodlash uchun
Structural = TemplateRef + ViewContainerRef; createEmbeddedView / clear; hasView flag bilan dublikatni oldini ol.
Nima bu?
* prefiksi (*ngIf="x") Angular microsyntax β qisqa yozuv. U aslida ng-template ga aylantiriladi: [ngIf]="x" property va #ngIf="ngIf" template ref. Custom structural directive ham *appMyDir="expr; param: value" sintaksisini @Input() setter'lar orqali qabul qiladi.
Kod misoli
import {
Directive,
Input,
TemplateRef,
ViewContainerRef,
inject,
} from '@angular/core';
interface SelectContext<T> {
$implicit: T;
appSelect: T;
index: number;
}
@Directive({
selector: '[appSelect]',
standalone: true,
})
export class SelectDirective<T> {
private templateRef = inject(TemplateRef<SelectContext<T>>);
private vcr = inject(ViewContainerRef);
@Input() set appSelect(source: T[] | null) {
this.vcr.clear();
if (!source) return;
source.forEach((item, index) => {
this.vcr.createEmbeddedView(this.templateRef, {
$implicit: item,
appSelect: item,
index,
});
});
}
}
<!-- *appSelect="products" desugar qilinganda: -->
<ul>
<ng-template appSelect let-item let-i="index" [appSelect]="products">
<li>{{ i + 1 }}. {{ item.name }}</li>
</ng-template>
</ul>
<!-- Microsyntax qisqa yozuvi (bir xil) -->
<ul>
<li *appSelect="products; let item; let i = index">
{{ i + 1 }}. {{ item.name }}
</li>
</ul>
TypeScript strict template checking (strictTemplates: true) let-itemning tipini SelectContext<T>dan chiqara olmaydi, agar directive static ngTemplateContextGuard metodini e'lon qilmasa. Bu static metod compiler'ga context tipini "isbotlab beradi" β bo'lmasa item any yoki xato tipda qoladi va template ichida type error tutilmaydi.
static ngTemplateContextGuard<T>(
dir: SelectDirective<T>,
ctx: unknown
): ctx is SelectContext<T> {
return true;
}
Imtihonda
*ngFor="let x of items"desugar qanday ko'rinishga ega?$implicitvalet-xbog'lanishi?- Custom microsyntax parametr (
let-i="index") qanday ishlaydi? ngTemplateContextGuardnima uchun kerak va bo'lmasa nima yo'qoladi?
Yodlash uchun
*dir = ng-template dir; $implicit = default let-x qiymati; type-safe context uchun ngTemplateContextGuard.
