diff --git a/apps/angular/4-typed-context-outlet/src/app/app.component.ts b/apps/angular/4-typed-context-outlet/src/app/app.component.ts index 23be9dac6..0cb7695c2 100644 --- a/apps/angular/4-typed-context-outlet/src/app/app.component.ts +++ b/apps/angular/4-typed-context-outlet/src/app/app.component.ts @@ -2,13 +2,14 @@ import { NgTemplateOutlet } from '@angular/common'; import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ListComponent } from './list.component'; import { PersonComponent } from './person.component'; +import { PersonDirective } from './person.directive'; @Component({ - imports: [NgTemplateOutlet, PersonComponent, ListComponent], + imports: [NgTemplateOutlet, PersonComponent, ListComponent, PersonDirective], selector: 'app-root', template: ` - + {{ name }}: {{ age }} diff --git a/apps/angular/4-typed-context-outlet/src/app/person.component.ts b/apps/angular/4-typed-context-outlet/src/app/person.component.ts index 59eb00ab1..2b45f50e2 100644 --- a/apps/angular/4-typed-context-outlet/src/app/person.component.ts +++ b/apps/angular/4-typed-context-outlet/src/app/person.component.ts @@ -1,13 +1,15 @@ -import { NgTemplateOutlet } from '@angular/common'; +import { CommonModule, NgTemplateOutlet } from '@angular/common'; import { Component, ContentChild, Input, TemplateRef } from '@angular/core'; +import { PersonDirective } from './person.directive'; +import { AppTemplateOutletDirective } from './templateOutlet.directive'; -interface Person { +export interface IPerson { name: string; age: number; } @Component({ - imports: [NgTemplateOutlet], + imports: [NgTemplateOutlet, AppTemplateOutletDirective, CommonModule], selector: 'person', template: ` ; } diff --git a/apps/angular/4-typed-context-outlet/src/app/person.directive.ts b/apps/angular/4-typed-context-outlet/src/app/person.directive.ts new file mode 100644 index 000000000..6c5c4cc51 --- /dev/null +++ b/apps/angular/4-typed-context-outlet/src/app/person.directive.ts @@ -0,0 +1,20 @@ +import { Directive } from '@angular/core'; + +interface IPersonContext { + $implicit: string; + name: string; + age: number; +} + +@Directive({ + selector: 'ng-template[person]', + standalone: true, +}) +export class PersonDirective { + static ngTemplateContextGuard( + dir: PersonDirective, + ctx: unknown, + ): ctx is IPersonContext { + return true; + } +} diff --git a/apps/angular/4-typed-context-outlet/src/app/templateOutlet.directive.ts b/apps/angular/4-typed-context-outlet/src/app/templateOutlet.directive.ts new file mode 100644 index 000000000..8877be9c5 --- /dev/null +++ b/apps/angular/4-typed-context-outlet/src/app/templateOutlet.directive.ts @@ -0,0 +1,58 @@ +import { + Directive, + EmbeddedViewRef, + Injector, + Input, + OnChanges, + SimpleChanges, + TemplateRef, + ViewContainerRef, +} from '@angular/core'; + +@Directive({ + selector: '[ngTemplateOutlet]', + standalone: true, +}) +// The directive is now waiting for a specific Type. +export class AppTemplateOutletDirective implements OnChanges { + private _viewRef: EmbeddedViewRef | null = null; + + @Input() public ngTemplateOutletContext: T | null = null; + + @Input() public ngTemplateOutlet: TemplateRef | null = null; + + @Input() public ngTemplateOutletInjector: Injector | null = null; + + constructor(private readonly _viewContainerRef: ViewContainerRef) {} + + ngOnChanges(changes: SimpleChanges) { + if (changes['ngTemplateOutlet'] || changes['ngTemplateOutletInjector']) { + const viewContainerRef = this._viewContainerRef; + + if (this._viewRef) { + viewContainerRef.remove(viewContainerRef.indexOf(this._viewRef)); + } + + if (this.ngTemplateOutlet) { + const { + ngTemplateOutlet: template, + ngTemplateOutletContext: context, + ngTemplateOutletInjector: injector, + } = this; + this._viewRef = viewContainerRef.createEmbeddedView( + template, + context, + injector ? { injector } : undefined, + ) as EmbeddedViewRef | null; + } else { + this._viewRef = null; + } + } else if ( + this._viewRef && + changes['ngTemplateOutletContext'] && + this.ngTemplateOutletContext + ) { + this._viewRef.context = this.ngTemplateOutletContext; + } + } +}