From 3e07e2977f84b9a0241a6894c0fbe2a4a9d44d00 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 6 Nov 2024 13:23:51 +0300 Subject: [PATCH] feat: resolve 3-directive-enhancement --- .../src/app/app.component.ts | 12 ++-- .../src/app/ng-for.directive.ts | 60 +++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 apps/angular/3-directive-enhancement/src/app/ng-for.directive.ts diff --git a/apps/angular/3-directive-enhancement/src/app/app.component.ts b/apps/angular/3-directive-enhancement/src/app/app.component.ts index cd1d5f23c..3834c6030 100644 --- a/apps/angular/3-directive-enhancement/src/app/app.component.ts +++ b/apps/angular/3-directive-enhancement/src/app/app.component.ts @@ -1,5 +1,5 @@ -import { NgFor, NgIf } from '@angular/common'; import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { NgForDirective } from './ng-for.directive'; interface Person { name: string; @@ -7,14 +7,12 @@ interface Person { @Component({ standalone: true, - imports: [NgFor, NgIf], + imports: [NgForDirective], selector: 'app-root', template: ` - -
- {{ person.name }} -
-
+
+ {{ person.name }} +
The list is empty !! `, styles: [], diff --git a/apps/angular/3-directive-enhancement/src/app/ng-for.directive.ts b/apps/angular/3-directive-enhancement/src/app/ng-for.directive.ts new file mode 100644 index 000000000..dc276da0b --- /dev/null +++ b/apps/angular/3-directive-enhancement/src/app/ng-for.directive.ts @@ -0,0 +1,60 @@ +import { + Directive, + effect, + inject, + input, + TemplateRef, + ViewContainerRef, +} from '@angular/core'; + +interface NgForDirectiveContext { + $implicit: T; +} + +@Directive({ + selector: '[appNgFor]', + standalone: true, +}) +export class NgForDirective { + private readonly viewContainer = inject(ViewContainerRef); + private readonly templateRef = inject(TemplateRef); + + appNgForOf = input(); + appNgForEmpty = input>(); + + constructor() { + effect(() => { + const items = this.appNgForOf(); + const empty = this.appNgForEmpty(); + this.render(items, empty); + }); + } + + private render(items?: T[], empty?: TemplateRef) { + if (items && items.length > 0) { + this.viewContainer.clear(); + items.forEach((item) => { + this.viewContainer.createEmbeddedView(this.templateRef, { + $implicit: item, + }); + }); + } else { + this.viewContainer.clear(); + if (empty) { + this.viewContainer.createEmbeddedView(empty); + } + } + } + + /** + * The guard body is not used at runtime, and included only to avoid + * TypeScript errors. + * @See https://angular.dev/guide/directives/structural-directives#typing-the-directives-context + */ + static ngTemplateContextGuard( + dir: NgForDirective, + ctx: any, + ): ctx is NgForDirectiveContext { + return true; + } +}